Sonner
Notificaciones en forma de tostadas apiladas para confirmaciones de guardado, subidas de archivos y ventanas de deshacer, con ese estilo neobrutalista de bordes y sombras.
"use client"
import { toast } from "sonner"Sonner pone en pantalla toasts apilados que se descartan solos a partir de una única llamada a toast(): monta un <Toaster /> y lanza notificaciones desde cualquier parte, sin cablear ningún contexto. No es una primitiva de Radix ni de Base UI: ambas variantes de backend envuelven la misma biblioteca Sonner, de emilkowalski, y siguen la receta neobrutalista: bordes gruesos, sombras marcadas y tipografía en negrita.
Recurre a este componente cuando:
- Confirmar acciones — «Guardado», «Copiado al portapapeles», «Ajustes actualizados» cuando se resuelve una mutación.
- Operaciones asíncronas —
toast.promise()sigue una subida o un despliegue desde la carga hasta el éxito o el error en un único toast. - Ventanas de deshacer — eliminaciones y archivados con un botón de acción, para que las operaciones destructivas tengan un periodo de gracia.
Acerca de#
Sonner está desarrollado y mantenido por emilkowalski.
Instalación#
Ejecuta el siguiente comando:
pnpm dlx shadcn@latest add https://neobrutalism.com/r/base/sonner.jsonnpx shadcn@latest add https://neobrutalism.com/r/base/sonner.jsonyarn dlx shadcn@latest add https://neobrutalism.com/r/base/sonner.jsonbunx --bun shadcn@latest add https://neobrutalism.com/r/base/sonner.json
Añade el componente Toaster.
import { Toaster } from "@/components/ui/sonner"
export default function RootLayout({ children }) {
return (
<html lang="en">
<head />
<body>
<main>{children}</main>
<Toaster />
</body>
</html>
)
}Instala las siguientes dependencias:
pnpm add sonner next-themesnpm install sonner next-themesyarn add sonner next-themesbun add sonner next-themes
Copia y pega el siguiente código en tu proyecto.
"use client"
import {
CircleCheckIcon,
InfoIcon,
Loader2Icon,
OctagonXIcon,
TriangleAlertIcon,
} from "lucide-react"
import { useTheme } from "next-themes"
import { Toaster as Sonner, type ToasterProps } from "sonner"
const Toaster = ({ ...props }: ToasterProps) => {
const { theme = "system" } = useTheme()
return (
<Sonner
theme={theme as ToasterProps["theme"]}
className="toaster group"
icons={{
success: <CircleCheckIcon className="size-4" />,
info: <InfoIcon className="size-4" />,
warning: <TriangleAlertIcon className="size-4" />,
error: <OctagonXIcon className="size-4" />,
loading: <Loader2Icon className="size-4 animate-spin" />,
}}
toastOptions={{
// Fully unstyled so the neobrutalist recipe below owns every surface:
// hard offset shadow, 2px border, square corners, press-down buttons.
unstyled: true,
classNames: {
toast:
"group/toast relative flex w-(--width) items-center gap-3 rounded border-2 border-border bg-popover p-4 font-sans text-popover-foreground shadow-md",
content: "flex min-w-0 flex-col gap-0.5",
title: "font-head text-sm font-medium",
description: "text-sm text-muted-foreground",
icon: "shrink-0",
actionButton:
"ms-auto h-fit min-w-fit shrink-0 rounded border-2 border-border bg-primary px-2 py-1 text-xs font-medium text-primary-foreground shadow-sm transition-all duration-200 hover:translate-x-0.5 hover:translate-y-0.5 hover:shadow-none",
cancelButton:
"ms-auto h-fit min-w-fit shrink-0 rounded border-2 border-border bg-muted px-2 py-1 text-xs font-medium text-foreground shadow-sm transition-all duration-200 hover:translate-x-0.5 hover:translate-y-0.5 hover:shadow-none",
closeButton:
"absolute -top-2 -start-2 rounded-full border-2 border-border bg-background p-0.5 transition-colors hover:bg-muted",
success: "[&_[data-icon]]:text-chart-2",
warning: "[&_[data-icon]]:text-chart-1",
error: "[&_[data-icon]]:text-destructive",
},
}}
{...props}
/>
)
}
export { Toaster }
Añade el componente Toaster.
import { Toaster } from "@/components/ui/sonner"
export default function RootLayout({ children }) {
return (
<html lang="en">
<head />
<body>
<Toaster />
<main>{children}</main>
</body>
</html>
)
}Uso#
import { toast } from "sonner"toast("Event has been created.")Ejemplos#
Tipos#
"use client"
import { toast } from "sonner"Descripción#
"use client"
import { toast } from "sonner"Posición#
Usa la prop position para cambiar la posición del toast.
"use client"
import { toast } from "sonner"Accesibilidad#
No existe un patrón APG de WAI-ARIA dedicado a los toasts; la guía más cercana es el patrón Alert. Sonner renderiza los toasts en una región viva ARIA de cortesía (polite), así que los lectores de pantalla los anuncian sin robar el foco. La región queda fuera del orden de tabulación normal (solo se alcanza mediante el atajo) y los temporizadores de descarte se pausan mientras la pila está bajo el cursor, tiene el foco o la pestaña está oculta.
Interacciones de teclado:
| Tecla | Acción |
|---|---|
Alt + T | Enfoca y expande la pila de toasts (configurable con la prop hotkey de Toaster) |
Tab / Shift + Tab | Recorre los toasts y sus botones de acción y de cierre |
Enter / Space | Activa el botón de acción o de cierre con foco |
Escape | Contrae la pila de toasts mientras el foco está dentro |
Referencia de API#
Consulta la referencia de API de Sonner para obtener más información.