Alert
BetaMensaje persistente dentro de la página sobre un estado, un resultado o algo que requiere atención. Incluye Banner.
registry/ds/alert.tsxInscripción confirmada
import { Alert } from "@/registry/ds/alert";
export default function AlertBasic() {
return (
<div className="w-full max-w-lg">
<Alert color="success" title="Inscripción confirmada">
Ya podés ver tus materias en el calendario.
</Alert>
</div>
);
}Cuál de los tres
Hay tres componentes de feedback. La pregunta es dónde vive el mensaje y cuánto dura.
| Componente | Dónde | Dura | Para qué |
|---|---|---|---|
| Alert | En el flujo de la página, junto a lo que afecta. | Hasta que se resuelve o se cierra. | Un estado que la persona tiene que ver para seguir. |
| Banner | Arriba de todo, ancho completo. | Mientras aplique. | Avisos de todo el sitio: mantenimiento, plazos. |
| Toast | Flotando, abajo a la derecha. | 5 segundos. | Confirmar que algo que la persona hizo, salió. |
Color
El color es el significado, y viene con su icono: nunca se elige por estética.
El sistema se actualiza el domingo a las 2:00.
Hay nuevas electivas disponibles para tu plan.
Guardamos tus cambios.
Tu inscripción vence en 3 días.
No pudimos procesar el pago.
import { Alert } from "@/registry/ds/alert";
export default function AlertColors() {
return (
<div className="flex w-full max-w-lg flex-col gap-3">
<Alert size="sm" color="neutral" title="El sistema se actualiza el domingo a las 2:00." />
<Alert size="sm" color="info" title="Hay nuevas electivas disponibles para tu plan." />
<Alert size="sm" color="success" title="Guardamos tus cambios." />
<Alert size="sm" color="warning" title="Tu inscripción vence en 3 días." />
<Alert size="sm" color="danger" title="No pudimos procesar el pago." />
</div>
);
}| Color | Cuándo |
|---|---|
neutral | Información sin carga: avisos operativos. |
info | Algo nuevo o útil que no requiere acción. |
success | Una acción salió bien y el resultado persiste. |
warning | Algo puede salir mal si no se actúa. |
danger | Algo salió mal o bloquea. Decí cómo resolverlo. |
Estilo
Subtle
Outline
Solid
import { Alert } from "@/registry/ds/alert";
export default function AlertVariants() {
return (
<div className="flex w-full max-w-lg flex-col gap-3">
<Alert color="warning" variant="subtle" title="Subtle">El default. Informa sin competir con la página.</Alert>
<Alert color="warning" variant="outline" title="Outline">Sobre fondos de color o cuando hay varios alerts juntos.</Alert>
<Alert color="warning" variant="solid" title="Solid">Máximo énfasis. Uno por pantalla, para lo que no puede pasarse por alto.</Alert>
</div>
);
}Con acción y cierre
Una sola acción por alert, y siempre que se pueda, la que resuelve el problema. Se puede cerrar solo si el mensaje no es imprescindible.
No pudimos procesar el pago
"use client";
import { useState } from "react";
import { Alert } from "@/registry/ds/alert";
import { Button } from "@/registry/ds/button";
import { ArrowUpRight } from "@/registry/ds/icons";
export default function AlertAction() {
const [open, setOpen] = useState(true);
if (!open) {
return (
<Button variant="tonal" size="sm" onClick={() => setOpen(true)}>
Volver a mostrar
</Button>
);
}
return (
<div className="w-full max-w-lg">
<Alert
color="danger"
role="alert"
title="No pudimos procesar el pago"
onDismiss={() => setOpen(false)}
action={
<Button variant="text" size="sm" iconRight={<ArrowUpRight />}>
Actualizar medio de pago
</Button>
}
>
La tarjeta terminada en 4821 fue rechazada. Tu inscripción queda reservada 48 horas.
</Alert>
</div>
);
}Tamaños
Small
Medium
Large
import { Alert } from "@/registry/ds/alert";
export default function AlertSizes() {
return (
<div className="flex w-full max-w-lg flex-col gap-3">
<Alert size="sm" color="info" title="Small">Dentro de cards, formularios y paneles.</Alert>
<Alert size="md" color="info" title="Medium">El default, en el flujo de la página.</Alert>
<Alert size="lg" color="info" title="Large">Encabezando una página o un estado vacío.</Alert>
</div>
);
}Banner
Inscripciones abiertasHasta el 30 de marzo para el primer semestre.
Mantenimiento programadoEl domingo de 2:00 a 4:00 el campus virtual no va a estar disponible.
import { Banner } from "@/registry/ds/alert";
import { Button } from "@/registry/ds/button";
export default function BannerBasic() {
return (
<div className="flex w-full flex-col gap-4">
<Banner color="info" title="Inscripciones abiertas" action={<Button variant="text" size="sm">Inscribirme</Button>}>
Hasta el 30 de marzo para el primer semestre.
</Banner>
<Banner color="warning" variant="solid" title="Mantenimiento programado">
El domingo de 2:00 a 4:00 el campus virtual no va a estar disponible.
</Banner>
</div>
);
}Banner: estilos
solid para lo que no puede pasar desapercibido, como una caída. subtle
para avisos normales. Sin ✕ cuando el aviso tiene que quedarse hasta que se
resuelva.
El campus está en mantenimientoVolvemos a las 6:00. Las inscripciones de hoy se extienden un día.
Inscripción confirmadaTe enviamos el detalle por correo.
Te falta la foto del carnetSin la foto no podés rendir finales.
"use client";
import { Banner } from "@/registry/ds/alert";
import { Button } from "@/registry/ds/button";
/** Solid para lo que no puede pasar desapercibido (una caída); subtle para avisos normales. Sin ✕ cuando el aviso tiene que quedarse */
export default function BannerVariants() {
return (
<div className="flex w-full flex-col gap-3">
<Banner
color="danger"
variant="solid"
title="El campus está en mantenimiento"
action={
// Sobre solid, la acción hereda el color on-solid: un link, no un Button
<a href="#" className="font-medium underline underline-offset-4 hover:opacity-80 focus-visible:outline-none focus-visible:shadow-[0_0_0_2px_var(--focus-ring)]">
Estado del sistema
</a>
}
>
Volvemos a las 6:00. Las inscripciones de hoy se extienden un día.
</Banner>
<Banner color="success" title="Inscripción confirmada" action={<Button size="sm" variant="text">Ver comprobante</Button>} onDismiss={() => {}}>
Te enviamos el detalle por correo.
</Banner>
<Banner color="warning" title="Te falta la foto del carnet" action={<Button size="sm" variant="text">Subirla</Button>}>
Sin la foto no podés rendir finales.
</Banner>
</div>
);
}Contenido
- Título = qué pasó. Descripción = por qué y qué hacer. Si entra en el título, no hace falta descripción.
- Específico y en lenguaje humano. Sin códigos de error, sin "Ups".
- Nunca culpes: "No pudimos procesar el pago", no "Ingresaste mal la tarjeta".
- Un alert por concepto. Tres alerts apilados son un problema de diseño, no de componente.
El archivo supera los 10 MB
Dice qué pasó y cómo seguir.
Error
"Error" y "ocurrió un error" no le sirven a nadie.
Medidas
| Size | Padding | Gap | Icono | Título | Descripción |
|---|---|---|---|---|---|
sm | spacing-xl 12 | 10 | 16 | Text sm / Medium | Text sm |
md | spacing-2xl 16 | 12 | 20 | Text md / Medium | Text sm |
lg | spacing-3xl 20 | 14 | 24 | Text lg / Medium | Text md |
Radio radius-lg (10). Borde border-sm (1). Banner: una fila, padding
10 × 16, sin radio, borde solo arriba y abajo.
Tokens por estilo
{rol} es info, success, warning o danger.
| Parte | Propiedad | Token |
|---|---|---|
| Subtle | Fondo | info/subtle |
| Subtle | Borde | info/border |
| Subtle · Outline | Título y texto | info/text |
| Subtle · Outline | Icono | info/accent |
| Outline | Fondo | bg/elevated |
| Solid | Fondo | info/solid |
| Solid | Texto e icono | info/on-solid |
| Neutral · Subtle | Fondo / borde | bg/surface |
| Neutral · Solid | Fondo | neutral/solid |
| Cerrar | Icono | icon/subtle |
warning/on-solid es oscuro (Yellow/12): el amarillo no admite texto blanco.
En Figma
| Propiedad en Figma | Valores | En código | Nota |
|---|---|---|---|
| Color | Neutral · Info · Success · Warning · Error | color | Error = danger en código, como el rol. |
| Style | Subtle · Outline · Solid | variant | — |
| Size | sm · md · lg | size | — |
| Title · Show title | Texto · on/off | title | — |
| Description · Show description | Texto · on/off | children | — |
| Action label · Show action | Texto · on/off | action | En código pasás el Button. |
| Show icon | on/off | icon | — |
| Dismissible | on/off | onDismiss | — |
Instalación
npx shadcn@latest add https://polen.cdc.cool/r/alert.jsonPlayground
Configurá el componente y copiá el snippet: se genera del mismo estado que renderiza el preview.
Tu inscripción vence en 3 días
<Alert title="Tu inscripción vence en 3 días">Completá el pago para conservar el cupo.</Alert>Props de Alert
| Prop | Tipo | Default | Descripción |
|---|---|---|---|
color | "neutral" | "info" | "success" | "warning" | "danger" | "neutral" | Significado. Define colores e icono. |
variant | "subtle" | "outline" | "solid" | "subtle" | Énfasis visual. |
size | "sm" | "md" | "lg" | "md" | Padding y tipografía. |
title | ReactNode | — | Qué pasó. |
children | ReactNode | — | Descripción. |
action | ReactNode | — | Una acción: Button variant="text" o un link. |
icon | boolean | true | Muestra el icono semántico. |
onDismiss | () => void | — | Si se pasa, aparece el botón de cerrar. |
role | "status" | "alert" | "none" | "status" | Cómo se anuncia. alert interrumpe: solo para errores que bloquean. |
Playground de Banner
Configurá el componente y copiá el snippet: se genera del mismo estado que renderiza el preview.
Mantenimiento programadoEl campus no estará disponible el sábado de 2:00 a 4:00.
<Banner color="info" title="Mantenimiento programado" action={<Button size="sm" variant="text">Ver detalles</Button>} onDismiss={close}>El campus no estará disponible el sábado de 2:00 a 4:00.</Banner>Banner acepta color, variant (subtle | solid), title, children,
action, icon y onDismiss.
Qué viene resuelto
role="status"por defecto: el lector de pantalla lo anuncia cuando termina lo que estaba leyendo, sin interrumpir.- El significado no depende del color: cada rol tiene su icono y el título lo dice en texto.
- El botón de cerrar tiene nombre accesible ("Cerrar") y foco visible.
Qué tenés que cuidar vos
role="alert"solo para errores que bloquean: interrumpe lo que se esté leyendo. Abusar de él entrena a ignorarlo.- El anuncio ocurre cuando el alert aparece en el DOM. Si ya estaba al
cargar la página, usá
role="none". - Al cerrarlo, devolvé el foco a un lugar lógico.
- Un error de formulario va junto al campo (Input
tiene
error); el Alert resume arriba cuando hay varios.