ToastStack
ToastStack é a região que a página monta uma vez para renderizar o que estiver na fila de toasts. Ela cuida de posição, empilhamento e dispensa; não decide quando um toast aparece — isso é trabalho do store, e qualquer código com acesso a ele pode enfileirar um.
React also exports a presentational ToastStack primitive with a forwarded root ref and a default
polite live region. ToastProvider composes it with separate announcement regions and owns timers
and focus behavior. This page documents the Alpine mount point and preserves its supported tabs.
Quando usar
Monte exatamente um ToastStack por documento, perto do fim do <body>, e deixe-o lá. Todo o resto
conversa com o store.
Prefira outra coisa quando:
- A mensagem pertence a um campo ou formulário específico — use Alert, que fica no fluxo, ao lado do que descreve, e não some sozinha.
- A mensagem precisa de resposta antes de qualquer outra coisa — use Dialog, que bloqueia.
- The page has nothing to announce yet — keep the empty stack mounted as the dismissal focus fallback; its focused state remains visible.
Acessibilidade
- A própria pilha não é viva. Duas regiões persistentes dentro dela existem antes de qualquer toast: educada para info e sucesso, assertiva para danger. Erros interrompem; o resto espera a vez.
- As linhas não carregam
rolepróprio — um nórole="status"inserido junto com o texto muitas vezes não é lido. - A dispensa é alcançável pelo teclado em todo toast — o temporizador é conveniência, nunca a única saída.
- Polite rows render before assertive rows, preserving queue order within each group.
Timing and dismissal
React ToastProvider and the Alpine toast store resolve duration when a notification is queued:
per-toast duration overrides explicit provider/store configuration, which overrides the implicit
tone policy. Info and success default to 8000 ms; danger, including error(), defaults to
persistent. 0 always means persistent. Explicit global 8000 also makes danger expire.
Changing configuration affects new notifications only.
Pointer hover and focus inside a row independently pause its remaining time. The countdown resumes
only after both leave; moving between descendants does not restart it. Give action-bearing React
messages an explicit { duration: 0 }; the provider does not inspect their content.
Dismissing a focused row returns focus to its enqueue-time opener if that element is still eligible. Removed, disabled, hidden or inert openers, and openers inside a toast stack, use the same persistent stack instead. This named region (a landmark) remains focusable and visibly outlined even when empty. Unfocused dismissals do not move focus, and deliberate action focus moves are preserved. The region adds no live announcement; polite and assertive regions announce additions only.
Migration: set duration={4000} on React ToastProvider or assign
Alpine.store('lyraToasts').duration = 4000 to restore the previous default delay for all tones.
Per-toast overrides still take precedence. These timing changes apply to React and Alpine; the
imported Blade API below is unchanged.
Alpine timers belong to the store and continue without a mounted stack. Destroying a renderer
releases only its own interaction claims; remounting does not reset lifetimes. The singleton
lyra:toast bridge forwards once to the latest registered store and messages remain plain text.
Reading duration initially returns 8000 without configuring it; any assignment, including
8000, makes it explicit. Existing markup needs no new row binding. The stack supplies
tabindex="-1", role="region" and "Notifications" when no accessible label is authored; provide
aria-label or aria-labelledby on the stack to localize it. Give coexisting stacks distinct
accessible names. React ToastProvider accepts aria-label for its owned notification region.
API e código
React: Em React a fila é renderizada pelo ToastProvider, não por um componente próprio.
x-data="lyraToastStack({ … })"
Este binding não recebe opções — monte e ele funciona.
A pilha não recebe opções — ela renderiza o que estiver no store. Monte uma por documento e
enfileire toasts de qualquer lugar com $store.lyraToasts:
<div class="lyra-toast-stack" x-data="lyraToastStack()">
<div
data-lyra-toast-region="polite"
aria-live="polite"
aria-relevant="additions"
style="display: contents"
>
<template x-for="toast in politeToasts" :key="toast.id">
<div class="lyra-toast">
<span class="lyra-toast__icon" :class="toneClass(toast.tone)"></span>
<span x-text="toast.message"></span>
<button class="lyra-toast__close" :data-toast-id="toast.id" x-bind="closeButton">×</button>
</div>
</template>
</div>
<div
data-lyra-toast-region="assertive"
aria-live="assertive"
aria-relevant="additions"
style="display: contents"
>
<template x-for="toast in assertiveToasts" :key="toast.id">
<div class="lyra-toast">
<span class="lyra-toast__icon" :class="toneClass(toast.tone)"></span>
<span x-text="toast.message"></span>
<button class="lyra-toast__close" :data-toast-id="toast.id" x-bind="closeButton">×</button>
</div>
</template>
</div>
</div>Cada toast carrega o próprio id, então o botão de fechar o lê do elemento em vez de um closure.
toneClass() mapeia o tom para o modificador do ícone; o ícone em si é você quem fornece.
<lyra:toast-stack> Gerado do lyra-ds/blade v0.10.0.
O comportamento vem de lyraToastStack() — instale @lyra-ds/alpine e veja a aba HTML + Alpine.
Este componente não recebe props — é só usar a tag.
<lyra:toast-stack />