Toast
.toast muestra un aviso breve sobre la página (por ejemplo, «Los cambios se guardaron») y se cierra solo a los 5 segundos. Necesita ds-uikit.js.
- Los toasts van dentro de
.toast-container, que los apila y llevaaria-live="polite". El contenedor debe estar en la página desde la carga. - Cada
.toastllevaaria-atomic="true"yhiddenmientras está cerrado. Dentro: ícono opcional (toast__icon), texto (toast__body, contoast__titleopcional) y el botón para cerrar (toast__close). - El botón que lo muestra lleva
data-ds-toggle="toast"ydata-ds-target="#id".
<button type="button" class="btn btn--primary" data-ds-toggle="toast" data-ds-target="#toast-basico">Mostrar toast</button>
<div class="toast-container" aria-live="polite"> <div class="toast" id="toast-basico" aria-atomic="true" hidden> <div class="toast__body">Los cambios se guardaron.</div> <button type="button" class="toast__close" data-ds-dismiss="toast" aria-label="Cerrar"></button> </div></div>export default function ToastBasico() { return ( <> <button type="button" className="btn btn--primary" data-ds-toggle="toast" data-ds-target="#toast-basico">Mostrar toast</button>
<div className="toast-container" aria-live="polite"> <div className="toast" id="toast-basico" aria-atomic="true" hidden> <div className="toast__body">Los cambios se guardaron.</div> <button type="button" className="toast__close" data-ds-dismiss="toast" aria-label="Cerrar" /> </div> </div> </> );}Ubica el contenedor al final del <body>, fuera de elementos con transform, filter o z-index propio. Queda sobre el header fijo y los modales (--ds-z-toast, 1090) y bajo el loader.
Variantes
Sección titulada «Variantes»toast--success, toast--danger, toast--warning y toast--info agregan una franja a la izquierda con el color del rol, y el ícono toma su tono fuerte. Para errores, agrega role="alert" al toast: se anuncia de inmediato.
<button type="button" class="btn" data-ds-toggle="toast" data-ds-target="#toast-exito">Éxito</button><button type="button" class="btn" data-ds-toggle="toast" data-ds-target="#toast-error">Error</button><button type="button" class="btn" data-ds-toggle="toast" data-ds-target="#toast-advertencia">Advertencia</button><button type="button" class="btn" data-ds-toggle="toast" data-ds-target="#toast-informacion">Información</button>
<div class="toast-container" aria-live="polite"> <div class="toast toast--success" id="toast-exito" aria-atomic="true"> <svg class="toast__icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="9" /><path d="m8 12 3 3 5-6" /></svg> <div class="toast__body">Tu pedido fue confirmado.</div> <button type="button" class="toast__close" data-ds-dismiss="toast" aria-label="Cerrar"></button> </div> <div class="toast toast--danger" id="toast-error" role="alert" aria-atomic="true"> <svg class="toast__icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="9" /><path d="m15 9-6 6M9 9l6 6" /></svg> <div class="toast__body">No se pudo enviar el formulario.</div> <button type="button" class="toast__close" data-ds-dismiss="toast" aria-label="Cerrar"></button> </div> <div class="toast toast--warning" id="toast-advertencia" aria-atomic="true"> <svg class="toast__icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10.3 3.9 2.4 17.5A2 2 0 0 0 4.1 20.5h15.8a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0Z" /><path d="M12 9v4M12 17h.01" /></svg> <div class="toast__body">Tu sesión vence en 5 minutos.</div> <button type="button" class="toast__close" data-ds-dismiss="toast" aria-label="Cerrar"></button> </div> <div class="toast toast--info" id="toast-informacion" aria-atomic="true"> <svg class="toast__icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="9" /><path d="M12 11v5M12 8h.01" /></svg> <div class="toast__body">Hay una nueva versión disponible.</div> <button type="button" class="toast__close" data-ds-dismiss="toast" aria-label="Cerrar"></button> </div></div>export default function ToastVariantes() { return ( <> <button type="button" className="btn" data-ds-toggle="toast" data-ds-target="#toast-exito">Éxito</button> <button type="button" className="btn" data-ds-toggle="toast" data-ds-target="#toast-error">Error</button> <button type="button" className="btn" data-ds-toggle="toast" data-ds-target="#toast-advertencia">Advertencia</button> <button type="button" className="btn" data-ds-toggle="toast" data-ds-target="#toast-informacion">Información</button>
<div className="toast-container" aria-live="polite"> <div className="toast toast--success" id="toast-exito" aria-atomic="true"> <svg className="toast__icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="9" /><path d="m8 12 3 3 5-6" /></svg> <div className="toast__body">Tu pedido fue confirmado.</div> <button type="button" className="toast__close" data-ds-dismiss="toast" aria-label="Cerrar" /> </div> <div className="toast toast--danger" id="toast-error" role="alert" aria-atomic="true"> <svg className="toast__icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="9" /><path d="m15 9-6 6M9 9l6 6" /></svg> <div className="toast__body">No se pudo enviar el formulario.</div> <button type="button" className="toast__close" data-ds-dismiss="toast" aria-label="Cerrar" /> </div> <div className="toast toast--warning" id="toast-advertencia" aria-atomic="true"> <svg className="toast__icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true"><path d="M10.3 3.9 2.4 17.5A2 2 0 0 0 4.1 20.5h15.8a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0Z" /><path d="M12 9v4M12 17h.01" /></svg> <div className="toast__body">Tu sesión vence en 5 minutos.</div> <button type="button" className="toast__close" data-ds-dismiss="toast" aria-label="Cerrar" /> </div> <div className="toast toast--info" id="toast-informacion" aria-atomic="true"> <svg className="toast__icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="9" /><path d="M12 11v5M12 8h.01" /></svg> <div className="toast__body">Hay una nueva versión disponible.</div> <button type="button" className="toast__close" data-ds-dismiss="toast" aria-label="Cerrar" /> </div> </div> </> );}Aquí empiezan visibles (sin hidden) para compararlos; los botones los vuelven a mostrar. Un toast visible al cargar no se cierra solo: el tiempo corre desde que se muestra con JS.
Con título
Sección titulada «Con título»toast__title destaca la primera línea. El ícono va antes de toast__body, con aria-hidden="true".
<button type="button" class="btn btn--primary" data-ds-toggle="toast" data-ds-target="#toast-titulo">Mostrar toast</button>
<div class="toast-container" aria-live="polite"> <div class="toast toast--success" id="toast-titulo" aria-atomic="true" hidden> <svg class="toast__icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="9" /><path d="m8 12 3 3 5-6" /></svg> <div class="toast__body"> <strong class="toast__title">Mensaje enviado</strong> <p>Te responderemos en un plazo de 24 horas hábiles.</p> </div> <button type="button" class="toast__close" data-ds-dismiss="toast" aria-label="Cerrar"></button> </div></div>export default function ToastTitulo() { return ( <> <button type="button" className="btn btn--primary" data-ds-toggle="toast" data-ds-target="#toast-titulo">Mostrar toast</button>
<div className="toast-container" aria-live="polite"> <div className="toast toast--success" id="toast-titulo" aria-atomic="true" hidden> <svg className="toast__icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="9" /><path d="m8 12 3 3 5-6" /></svg> <div className="toast__body"> <strong className="toast__title">Mensaje enviado</strong> <p>Te responderemos en un plazo de 24 horas hábiles.</p> </div> <button type="button" className="toast__close" data-ds-dismiss="toast" aria-label="Cerrar" /> </div> </div> </> );}Posiciones
Sección titulada «Posiciones»Por defecto, arriba a la derecha. Cambia la ubicación con un modificador del contenedor: toast-container--top-start, --top-center, --bottom-start, --bottom-center o --bottom-end. Usa un contenedor por posición. En pantallas angostas, los toasts ocupan el ancho disponible menos el margen.
<button type="button" class="btn" data-ds-toggle="toast" data-ds-target="#toast-top-start">Arriba a la izquierda</button><button type="button" class="btn" data-ds-toggle="toast" data-ds-target="#toast-top-center">Arriba al centro</button><button type="button" class="btn" data-ds-toggle="toast" data-ds-target="#toast-top-end">Arriba a la derecha</button><button type="button" class="btn" data-ds-toggle="toast" data-ds-target="#toast-bottom-start">Abajo a la izquierda</button><button type="button" class="btn" data-ds-toggle="toast" data-ds-target="#toast-bottom-center">Abajo al centro</button><button type="button" class="btn" data-ds-toggle="toast" data-ds-target="#toast-bottom-end">Abajo a la derecha</button>
<div class="toast-container toast-container--top-start" aria-live="polite"> <div class="toast" id="toast-top-start" aria-atomic="true" hidden> <div class="toast__body">Arriba a la izquierda</div> <button type="button" class="toast__close" data-ds-dismiss="toast" aria-label="Cerrar"></button> </div></div>
<div class="toast-container toast-container--top-center" aria-live="polite"> <div class="toast" id="toast-top-center" aria-atomic="true" hidden> <div class="toast__body">Arriba al centro</div> <button type="button" class="toast__close" data-ds-dismiss="toast" aria-label="Cerrar"></button> </div></div>
<div class="toast-container" aria-live="polite"> <div class="toast" id="toast-top-end" aria-atomic="true" hidden> <div class="toast__body">Arriba a la derecha (por defecto)</div> <button type="button" class="toast__close" data-ds-dismiss="toast" aria-label="Cerrar"></button> </div></div>
<div class="toast-container toast-container--bottom-start" aria-live="polite"> <div class="toast" id="toast-bottom-start" aria-atomic="true" hidden> <div class="toast__body">Abajo a la izquierda</div> <button type="button" class="toast__close" data-ds-dismiss="toast" aria-label="Cerrar"></button> </div></div>
<div class="toast-container toast-container--bottom-center" aria-live="polite"> <div class="toast" id="toast-bottom-center" aria-atomic="true" hidden> <div class="toast__body">Abajo al centro</div> <button type="button" class="toast__close" data-ds-dismiss="toast" aria-label="Cerrar"></button> </div></div>
<div class="toast-container toast-container--bottom-end" aria-live="polite"> <div class="toast" id="toast-bottom-end" aria-atomic="true" hidden> <div class="toast__body">Abajo a la derecha</div> <button type="button" class="toast__close" data-ds-dismiss="toast" aria-label="Cerrar"></button> </div></div>export default function ToastPosiciones() { return ( <> <button type="button" className="btn" data-ds-toggle="toast" data-ds-target="#toast-top-start">Arriba a la izquierda</button> <button type="button" className="btn" data-ds-toggle="toast" data-ds-target="#toast-top-center">Arriba al centro</button> <button type="button" className="btn" data-ds-toggle="toast" data-ds-target="#toast-top-end">Arriba a la derecha</button> <button type="button" className="btn" data-ds-toggle="toast" data-ds-target="#toast-bottom-start">Abajo a la izquierda</button> <button type="button" className="btn" data-ds-toggle="toast" data-ds-target="#toast-bottom-center">Abajo al centro</button> <button type="button" className="btn" data-ds-toggle="toast" data-ds-target="#toast-bottom-end">Abajo a la derecha</button>
<div className="toast-container toast-container--top-start" aria-live="polite"> <div className="toast" id="toast-top-start" aria-atomic="true" hidden> <div className="toast__body">Arriba a la izquierda</div> <button type="button" className="toast__close" data-ds-dismiss="toast" aria-label="Cerrar" /> </div> </div>
<div className="toast-container toast-container--top-center" aria-live="polite"> <div className="toast" id="toast-top-center" aria-atomic="true" hidden> <div className="toast__body">Arriba al centro</div> <button type="button" className="toast__close" data-ds-dismiss="toast" aria-label="Cerrar" /> </div> </div>
<div className="toast-container" aria-live="polite"> <div className="toast" id="toast-top-end" aria-atomic="true" hidden> <div className="toast__body">Arriba a la derecha (por defecto)</div> <button type="button" className="toast__close" data-ds-dismiss="toast" aria-label="Cerrar" /> </div> </div>
<div className="toast-container toast-container--bottom-start" aria-live="polite"> <div className="toast" id="toast-bottom-start" aria-atomic="true" hidden> <div className="toast__body">Abajo a la izquierda</div> <button type="button" className="toast__close" data-ds-dismiss="toast" aria-label="Cerrar" /> </div> </div>
<div className="toast-container toast-container--bottom-center" aria-live="polite"> <div className="toast" id="toast-bottom-center" aria-atomic="true" hidden> <div className="toast__body">Abajo al centro</div> <button type="button" className="toast__close" data-ds-dismiss="toast" aria-label="Cerrar" /> </div> </div>
<div className="toast-container toast-container--bottom-end" aria-live="polite"> <div className="toast" id="toast-bottom-end" aria-atomic="true" hidden> <div className="toast__body">Abajo a la derecha</div> <button type="button" className="toast__close" data-ds-dismiss="toast" aria-label="Cerrar" /> </div> </div> </> );}Duración
Sección titulada «Duración»data-ds-delay cambia el tiempo en milisegundos y data-ds-autohide="false" desactiva el cierre automático. Usa el segundo cuando el aviso tenga un enlace o una acción.
<button type="button" class="btn" data-ds-toggle="toast" data-ds-target="#toast-diez">10 segundos</button><button type="button" class="btn" data-ds-toggle="toast" data-ds-target="#toast-fijo">Sin cierre automático</button>
<div class="toast-container" aria-live="polite"> <div class="toast" id="toast-diez" data-ds-delay="10000" aria-atomic="true" hidden> <div class="toast__body">Este aviso se cierra a los 10 segundos.</div> <button type="button" class="toast__close" data-ds-dismiss="toast" aria-label="Cerrar"></button> </div> <div class="toast toast--info" id="toast-fijo" data-ds-autohide="false" aria-atomic="true" hidden> <svg class="toast__icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="9" /><path d="M12 11v5M12 8h.01" /></svg> <div class="toast__body"> <strong class="toast__title">Actualización disponible</strong> <p>Este aviso queda abierto hasta que lo cierres.</p> </div> <button type="button" class="toast__close" data-ds-dismiss="toast" aria-label="Cerrar"></button> </div></div>export default function ToastDuracion() { return ( <> <button type="button" className="btn" data-ds-toggle="toast" data-ds-target="#toast-diez">10 segundos</button> <button type="button" className="btn" data-ds-toggle="toast" data-ds-target="#toast-fijo">Sin cierre automático</button>
<div className="toast-container" aria-live="polite"> <div className="toast" id="toast-diez" data-ds-delay="10000" aria-atomic="true" hidden> <div className="toast__body">Este aviso se cierra a los 10 segundos.</div> <button type="button" className="toast__close" data-ds-dismiss="toast" aria-label="Cerrar" /> </div> <div className="toast toast--info" id="toast-fijo" data-ds-autohide="false" aria-atomic="true" hidden> <svg className="toast__icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="9" /><path d="M12 11v5M12 8h.01" /></svg> <div className="toast__body"> <strong className="toast__title">Actualización disponible</strong> <p>Este aviso queda abierto hasta que lo cierres.</p> </div> <button type="button" className="toast__close" data-ds-dismiss="toast" aria-label="Cerrar" /> </div> </div> </> );}JavaScript
Sección titulada «JavaScript»- Se muestra con
data-ds-toggle="toast". Si ya está abierto, el tiempo vuelve a empezar. - Se cierra con
data-ds-dismiss="toast"o solo, a los 5 segundos. El tiempo se pausa mientras el puntero está encima o el foco está dentro, y sigue al salir. - No atrapa el foco ni se cierra con Escape. Aparece y desaparece con un fundido y un leve desplazamiento. Queda oculto con
hidden, sin quitarlo del DOM.
| Atributo | Qué hace |
|---|---|
data-ds-toggle="toast" |
En el botón: muestra el toast indicado en data-ds-target (en un enlace, también sirve href="#id"). Si ya está abierto, reinicia el tiempo. |
data-ds-dismiss="toast" |
Cierra el toast que contiene al botón. |
data-ds-delay="<ms>" |
En .toast: tiempo hasta cerrarse. Por defecto, 5000. |
data-ds-autohide="false" |
En .toast: no se cierra solo. |
const aviso = dsUIKit.toast('#toast-guardado'); // elemento o selectoraviso.open(); // lo muestra (si ya está abierto, reinicia el tiempo)aviso.close();aviso.toggle();aviso.isOpen; // true o false
// Mostrar un aviso que viene del servidor al cargar la páginadsUIKit.toast('#aviso-servidor')?.open();En React, los atributos funcionan igual. Para mostrarlo después de una acción, llama a open() con la referencia del toast. Pon el contenedor una sola vez, en un componente que esté siempre montado (por ejemplo, el layout).
import { useRef } from 'react';import { toast } from './js/ds-uikit.esm.js';
export default function Guardar() { const ref = useRef(null);
const guardar = async () => { await enviar(); toast(ref.current).open(); };
return ( <> <button type="button" className="btn btn--primary" onClick={guardar}>Guardar</button>
<div className="toast-container" aria-live="polite"> <div ref={ref} className="toast" aria-atomic="true" hidden> <div className="toast__body">Los cambios se guardaron.</div> <button type="button" className="toast__close" data-ds-dismiss="toast" aria-label="Cerrar" /> </div> </div> </> );}| Evento | Cuándo |
|---|---|
ds:open |
Antes de mostrarse. Con preventDefault() se cancela. |
ds:opened |
Al terminar de mostrarse. |
ds:close |
Antes de cerrarse. Cancelable. |
ds:closed |
Al terminar de cerrarse. |
event.detail.trigger es el botón que lo mostró o cerró, o null si se cerró solo o fue por la API. Más detalles en JavaScript.
Accesibilidad
Sección titulada «Accesibilidad».toast-containeres la región viva (aria-live="polite"): los lectores de pantalla leen el toast al mostrarse, sin interrumpir. Debe existir en la página antes de mostrar un toast; si se crea junto con él, algunos lectores no lo anuncian.aria-atomic="true"hace que se lea el toast completo. Para errores,role="alert"en el toast lo anuncia de inmediato.- No dependas solo del color: el texto debe decir si es un éxito, un error o un aviso. Los íconos van con
aria-hidden="true". - Cinco segundos pueden ser poco para leer: el tiempo se pausa con el puntero encima o el foco dentro. Si el aviso tiene un enlace o una acción, usa
data-ds-autohide="false". - Si el foco estaba dentro al cerrarse, vuelve a donde estaba antes (o pasa al siguiente elemento enfocable).
- La X lleva
type="button"yaria-label="Cerrar". - Con «reducir movimiento» activado, aparece y se cierra sin transición.
- Con los colores por defecto, el ícono de
toast--warning(2,6:1) queda bajo el contraste de 3:1. La franja es decorativa.
| Clase | Uso |
|---|---|
toast-container |
Contenedor fijo (arriba a la derecha) que apila los toasts. Lleva aria-live="polite". |
toast-container--{posición} |
top-start, top-center, bottom-start, bottom-center, bottom-end. |
toast |
Base. Lleva hidden mientras está cerrado. |
toast--{rol} |
success, danger, warning, info. |
toast__icon |
Ícono SVG, con aria-hidden="true". |
toast__body |
Texto. |
toast__title |
Título del toast. |
toast__close |
Botón para cerrar, con data-ds-dismiss="toast". |
Variables
Sección titulada «Variables»| Variable | Valor por defecto | Uso |
|---|---|---|
--ds-toast-container-width | 26.25rem | Ancho máximo de los toasts. |
--ds-toast-container-margin | var(--ds-space-4) | Separación con los bordes de la pantalla. |
--ds-toast-container-gap | var(--ds-space-2) | Separación entre toasts. |
--ds-toast-container-z-index | var(--ds-z-toast) | Capa de los toasts (z-index). |
| Variable | Valor por defecto | Uso |
|---|---|---|
--ds-toast-bg | var(--ds-color-surface) | Fondo. |
--ds-toast-color | var(--ds-color-text) | Color del texto. |
--ds-toast-border-color | var(--ds-color-border) | Color del borde. |
--ds-toast-accent-color | var(--ds-toast-border-color) | Franja a la izquierda: color (en las variantes, el del rol). |
--ds-toast-accent-width | 0.25rem | Franja a la izquierda: grosor. |
--ds-toast-icon-color | currentColor | Color del ícono (toast__icon). |
--ds-toast-padding-y | 0.875rem | Espacio vertical interno. |
--ds-toast-padding-x | 1rem | Espacio horizontal interno. |
--ds-toast-gap | 0.75rem | Separación entre ícono, texto y botón para cerrar. |
--ds-toast-font-size | var(--ds-font-size-sm) | |
--ds-toast-radius | var(--ds-radius-md) | |
--ds-toast-shadow | var(--ds-shadow-lg) | |
--ds-toast-close-size | 2rem | Tamaño del botón para cerrar (toast__close). |
--ds-toast-offset | -0.5rem | Desplazamiento vertical al aparecer y al cerrarse (abajo, 0.5rem). |
--ds-toast-transition-duration | var(--ds-duration-fast) | Duración del fundido. |