Dialog
Dialog é um modal controlado com portal, retenção de foco, bloqueio de rolagem e caminhos de fechamento acessíveis.
Exemplos
Confirmando uma ação destrutiva
O rodapé é onde as ações moram — o caminho de cancelar primeiro, o destrutivo por último.
Bloqueando o fechamento acidental
Desligue closeOnEsc e closeOnOverlayClick só quando perder o diálogo significar perder
trabalho ou pular uma decisão. Nunca remova todos os caminhos de fechamento: o × aparece sempre
que onClose está definido.
Quando usar
Use um Dialog para uma decisão curta e focada que precisa ser resolvida antes de o usuário seguir em frente: confirmar uma exclusão, nomear um recurso novo, revisar termos.
Prefira outro componente quando:
- O conteúdo é longo ou a tarefa é uma jornada paralela — use Drawer, que entra deslizando sem tomar a tela inteira.
- Você só precisa relatar o resultado de algo — use Toast (transitório) ou Alert (persistente, inline).
- O painel é ancorado a um controle e contém opções — use Dropdown.
Acessibilidade
- O painel é
role="dialog"comaria-modal, nomeado pelotitleviaaria-labelledby. - O foco entra no painel na abertura, fica retido enquanto ele está aberto e volta para o elemento que o abriu no fechamento.
- Todo caminho de fechamento chama
onClose: o botão ×, o Escape e o clique no backdrop. O × aparece só quandoonCloseé fornecido, então um diálogo nunca fica sem uma saída visível. - O botão × tem o nome "Close" por padrão. Passe
closeLabelpara traduzir seu nome acessível. - A rolagem da página fica bloqueada enquanto o diálogo está aberto, e o painel é portado para o
document.body, escapando de qualquer ancestral comoverflow: hidden.
API e código
| Nome | Tipo | Obrigatória | Descrição |
|---|---|---|---|
open | boolean | Obrigatória | Controls visibility. `true` mounts the overlay + panel; `false` plays the exit then unmounts. |
onClose | () => void | — | Called by every close path (Esc, overlay click, the × button). The × renders only when this is provided. |
closeLabel | string | — | Accessible name for the close button. Default: `"Close"`. |
title | ReactNode | Obrigatória | Heading rendered in the panel header and wired as the accessible name via `aria-labelledby`. |
footer | ReactNode | — | Action buttons rendered in the footer. Omitted → no `.lyra-dialog__footer` chrome. |
closeOnEsc | boolean | — | Close on the Escape key. Default `true`. |
closeOnOverlayClick | boolean | — | Close on a click on the overlay backdrop (never on panel content). Default `true`. |
container | HTMLElement | — | Portal host. Defaults to `document.body`. |
children | ReactNode | Obrigatória | Body content. |
x-data="lyraDialog({ … })"
| Opção | Tipo | Obrigatória | Descrição |
|---|---|---|---|
defaultOpen | boolean | — | |
closeOnEsc | boolean | — | |
closeOnOverlayClick | boolean | — | |
labelId | string | — |
Sem React, componha as mesmas classes — o estado de abertura, o foco e o Escape ficam com você:
<div class="lyra-dialog-overlay">
<div class="lyra-dialog" role="dialog" aria-modal="true" aria-labelledby="dialog-title">
<div class="lyra-dialog__header">
<h2 class="lyra-dialog__title" id="dialog-title">Excluir projeto</h2>
<button class="lyra-dialog__close" aria-label="Fechar">✕</button>
</div>
<div class="lyra-dialog__body">Esta ação não pode ser desfeita.</div>
<div class="lyra-dialog__footer">
<button class="lyra-btn lyra-btn--ghost lyra-btn--md">Cancelar</button>
<button class="lyra-btn lyra-btn--danger lyra-btn--md">Excluir</button>
</div>
</div>
</div><lyra:dialog> Gerado do lyra-ds/blade v0.10.0.
O comportamento vem de lyraDialog() — instale @lyra-ds/alpine e veja a aba HTML + Alpine.
| Prop | Padrão | Obrigatória | Valores de exemplo |
|---|---|---|---|
title | — | Obrigatória | — |
closable | true | — | — |
closeLabel | 'Close' | — | — |
defaultOpen | false | — | — |
closeOnEsc | true | — | — |
closeOnOverlayClick | true | — | — |
labelId | null | — | — |
<lyra:dialog title="Delete project" close-label="Close">
This permanently deletes the project and every issue attached to it.
</lyra:dialog>