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" com aria-modal, nomeado pelo title via aria-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ó quando onClose é 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 closeLabel para 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 com overflow: hidden.

API e código

NomeTipoObrigatóriaDescrição
openbooleanObrigatóriaControls visibility. `true` mounts the overlay + panel; `false` plays the exit then unmounts.
onClose() => voidCalled by every close path (Esc, overlay click, the × button). The × renders only when this is provided.
closeLabelstringAccessible name for the close button. Default: `"Close"`.
titleReactNodeObrigatóriaHeading rendered in the panel header and wired as the accessible name via `aria-labelledby`.
footerReactNodeAction buttons rendered in the footer. Omitted → no `.lyra-dialog__footer` chrome.
closeOnEscbooleanClose on the Escape key. Default `true`.
closeOnOverlayClickbooleanClose on a click on the overlay backdrop (never on panel content). Default `true`.
containerHTMLElementPortal host. Defaults to `document.body`.
childrenReactNodeObrigatóriaBody content.

x-data="lyraDialog({ … })"

OpçãoTipoObrigatóriaDescrição
defaultOpenboolean
closeOnEscboolean
closeOnOverlayClickboolean
labelIdstring

Sem React, componha as mesmas classes — o estado de abertura, o foco e o Escape ficam com você:

html
<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.

PropPadrãoObrigatóriaValores de exemplo
titleObrigatória
closabletrue
closeLabel'Close'
defaultOpenfalse
closeOnEsctrue
closeOnOverlayClicktrue
labelIdnull
blade
<lyra:dialog title="Delete project" close-label="Close">
    This permanently deletes the project and every issue attached to it.
</lyra:dialog>