Ir al contenido

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 lleva aria-live="polite". El contenedor debe estar en la página desde la carga.
  • Cada .toast lleva aria-atomic="true" y hidden mientras está cerrado. Dentro: ícono opcional (toast__icon), texto (toast__body, con toast__title opcional) y el botón para cerrar (toast__close).
  • El botón que lo muestra lleva data-ds-toggle="toast" y data-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>

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.

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>

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.

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>

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>

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>
  • 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 selector
aviso.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ágina
dsUIKit.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.

  • .toast-container es 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" y aria-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".
VariableValor por defectoUso
--ds-toast-container-width26.25remAncho máximo de los toasts.
--ds-toast-container-marginvar(--ds-space-4)Separación con los bordes de la pantalla.
--ds-toast-container-gapvar(--ds-space-2)Separación entre toasts.
--ds-toast-container-z-indexvar(--ds-z-toast)Capa de los toasts (z-index).
VariableValor por defectoUso
--ds-toast-bgvar(--ds-color-surface)Fondo.
--ds-toast-colorvar(--ds-color-text)Color del texto.
--ds-toast-border-colorvar(--ds-color-border)Color del borde.
--ds-toast-accent-colorvar(--ds-toast-border-color)Franja a la izquierda: color (en las variantes, el del rol).
--ds-toast-accent-width0.25remFranja a la izquierda: grosor.
--ds-toast-icon-colorcurrentColorColor del ícono (toast__icon).
--ds-toast-padding-y0.875remEspacio vertical interno.
--ds-toast-padding-x1remEspacio horizontal interno.
--ds-toast-gap0.75remSeparación entre ícono, texto y botón para cerrar.
--ds-toast-font-sizevar(--ds-font-size-sm)
--ds-toast-radiusvar(--ds-radius-md)
--ds-toast-shadowvar(--ds-shadow-lg)
--ds-toast-close-size2remTamaño del botón para cerrar (toast__close).
--ds-toast-offset-0.5remDesplazamiento vertical al aparecer y al cerrarse (abajo, 0.5rem).
--ds-toast-transition-durationvar(--ds-duration-fast)Duración del fundido.