Dialog
Janela modal para foco em uma tarefa ou informação crítica, com trap de foco e suporte a teclado.
O mk-dialog renderiza um painel modal sobre um backdrop que bloqueia a interação com o restante da página até que o usuário tome uma decisão ou o dispense. Gerencia foco automaticamente (trap de foco, restauração ao fechar) e suporta fechamento via tecla Escape, clique no backdrop e botão X. A composição é feita com três subcomponentes: mk-dialog-header, mk-dialog-body e mk-dialog-footer. Por interromper o fluxo da interface, deve ser usado com parcimônia — cada abertura de dialog representa uma quebra de contexto para o usuário.
Quando usar
O dialog é adequado quando a tarefa exige atenção total antes de prosseguir.
Use quando:- O usuário precisa confirmar uma ação antes que ela seja executada, especialmente ações destrutivas.
- Um formulário curto precisa ser preenchido sem navegar para outra página.
- Informações críticas precisam ser lidas ou reconhecidas antes de continuar.
- O conteúdo for extenso — use uma página ou drawer dedicado.
- A informação for apenas notificacional e não exigir resposta — use um
mk-toast. - O contexto puder ser preservado com um painel lateral.
Anatomia
O dialog é composto por três regiões empilhadas verticalmente, cada uma representada por um subcomponente dedicado.
| # | Subcomponente | Obrigatório? | Função |
|---|---|---|---|
| 1 | mk-dialog-header | Sim | Cabeçalho do dialog. Aceita texto simples como título ou conteúdo customizado. O botão de fechar (×) é renderizado automaticamente pelo mk-dialog. |
| 2 | mk-dialog-body | Sim | Área de conteúdo flexível para texto explicativo, formulários ou qualquer conteúdo relevante. |
| 3 | mk-dialog-footer | Não | Rodapé de ações. Alinha os botões horizontalmente com justify-content: flex-end automaticamente. |
Padrão
A estrutura completa usa mk-dialog-header, mk-dialog-body e mk-dialog-footer como filhos diretos de mk-dialog.
import { useState } from 'react';
import { MkDialog, MkDialogHeader, MkDialogBody, MkDialogFooter, MkButton } from '@db1/makuco-ui-react';
function App() {
const [open, setOpen] = useState(false);
return (
<>
<MkButton onMkClick={() => setOpen(true)}>Abrir dialog</MkButton>
<MkDialog open={open} onMkClose={() => setOpen(false)}>
<MkDialogHeader>Confirmar ação</MkDialogHeader>
<MkDialogBody>
<p>Tem certeza que deseja continuar?</p>
</MkDialogBody>
<MkDialogFooter>
<MkButton variant="outlined" onMkClick={() => setOpen(false)}>Cancelar</MkButton>
<MkButton onMkClick={handleConfirm}>Confirmar</MkButton>
</MkDialogFooter>
</MkDialog>
</>
);
}<mk-button (mkClick)="open = true">Abrir dialog</mk-button>
<mk-dialog [open]="open" (mkClose)="open = false">
<mk-dialog-header>Confirmar ação</mk-dialog-header>
<mk-dialog-body>
<p>Tem certeza que deseja continuar?</p>
</mk-dialog-body>
<mk-dialog-footer>
<mk-button variant="outlined" (mkClick)="open = false">Cancelar</mk-button>
<mk-button (mkClick)="handleConfirm()">Confirmar</mk-button>
</mk-dialog-footer>
</mk-dialog>Ação destrutiva
Para ações de alto risco, use kind="destructive" no botão de confirmação. O header pode receber conteúdo customizado com ícone via mk-dialog-header.
<MkDialog open={open} onMkClose={() => setOpen(false)}>
<MkDialogHeader>Excluir registro</MkDialogHeader>
<MkDialogBody>
<p>Esta ação é permanente. O registro será removido e não poderá ser recuperado.</p>
</MkDialogBody>
<MkDialogFooter>
<MkButton variant="outlined" onMkClick={() => setOpen(false)}>Cancelar</MkButton>
<MkButton kind="destructive" onMkClick={handleDelete}>Excluir</MkButton>
</MkDialogFooter>
</MkDialog><mk-dialog [open]="open" (mkClose)="open = false">
<mk-dialog-header>Excluir registro</mk-dialog-header>
<mk-dialog-body>
<p>Esta ação é permanente. O registro será removido e não poderá ser recuperado.</p>
</mk-dialog-body>
<mk-dialog-footer>
<mk-button variant="outlined" (mkClick)="open = false">Cancelar</mk-button>
<mk-button kind="destructive" (mkClick)="handleDelete()">Excluir</mk-button>
</mk-dialog-footer>
</mk-dialog>Tamanhos
<MkDialog open={open} size="sm" onMkClose={() => setOpen(false)}>
<MkDialogHeader>Dialog SM</MkDialogHeader>
<MkDialogBody>...</MkDialogBody>
</MkDialog>
<MkDialog open={open} size="lg" onMkClose={() => setOpen(false)}>
<MkDialogHeader>Dialog LG</MkDialogHeader>
<MkDialogBody>...</MkDialogBody>
</MkDialog><mk-dialog [open]="open" size="sm" (mkClose)="open = false">
<mk-dialog-header>Dialog SM</mk-dialog-header>
<mk-dialog-body>...</mk-dialog-body>
</mk-dialog>
<mk-dialog [open]="open" size="lg" (mkClose)="open = false">
<mk-dialog-header>Dialog LG</mk-dialog-header>
<mk-dialog-body>...</mk-dialog-body>
</mk-dialog>Sem fechar no backdrop
<MkDialog open={open} closeOnBackdrop={false} onMkClose={() => setOpen(false)}>
<MkDialogHeader>Ação obrigatória</MkDialogHeader>
<MkDialogBody>
<p>Você precisa tomar uma decisão para fechar este dialog.</p>
</MkDialogBody>
<MkDialogFooter>
<MkButton variant="outlined" onMkClick={() => setOpen(false)}>Cancelar</MkButton>
<MkButton onMkClick={handleConfirm}>Confirmar</MkButton>
</MkDialogFooter>
</MkDialog><mk-dialog [open]="open" [close-on-backdrop]="false" (mkClose)="open = false">
<mk-dialog-header>Ação obrigatória</mk-dialog-header>
<mk-dialog-body>
<p>Você precisa tomar uma decisão para fechar este dialog.</p>
</mk-dialog-body>
<mk-dialog-footer>
<mk-button variant="outlined" (mkClick)="open = false">Cancelar</mk-button>
<mk-button (mkClick)="handleConfirm()">Confirmar</mk-button>
</mk-dialog-footer>
</mk-dialog>Header personalizado
Passe conteúdo customizado dentro de mk-dialog-header para substituir o título por texto enriquecido, ícone ou qualquer markup.
import { MkDialog, MkDialogHeader, MkDialogBody, MkDialogFooter, MkButton, MkIcon } from '@db1/makuco-ui-react';
<MkDialog open={open} onMkClose={() => setOpen(false)}>
<MkDialogHeader>
<div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
<MkIcon name="triangle-alert" size="md" />
<span className="mk-typography-heading-sm-semi-bold">Ação destrutiva</span>
</div>
</MkDialogHeader>
<MkDialogBody>
<p>Esta ação não pode ser desfeita. Tem certeza que deseja continuar?</p>
</MkDialogBody>
<MkDialogFooter>
<MkButton variant="outlined" onMkClick={() => setOpen(false)}>Cancelar</MkButton>
<MkButton kind="destructive" onMkClick={handleConfirm}>Confirmar</MkButton>
</MkDialogFooter>
</MkDialog><mk-dialog [open]="open" (mkClose)="open = false">
<mk-dialog-header>
<div style="display: flex; align-items: center; gap: 8px;">
<mk-icon name="triangle-alert" size="md"></mk-icon>
<span class="mk-typography-heading-sm-semi-bold">Ação destrutiva</span>
</div>
</mk-dialog-header>
<mk-dialog-body>
<p>Esta ação não pode ser desfeita. Tem certeza que deseja continuar?</p>
</mk-dialog-body>
<mk-dialog-footer>
<mk-button variant="outlined" (mkClick)="open = false">Cancelar</mk-button>
<mk-button kind="destructive" (mkClick)="handleConfirm()">Confirmar</mk-button>
</mk-dialog-footer>
</mk-dialog>Comportamento
O dialog abre sobre um overlay escurecido que bloqueia a interação com o conteúdo ao fundo. Ao abrir, o foco é movido automaticamente para dentro do painel. O usuário pode fechar o dialog pelo botão ×, pelos botões do footer, clicando no backdrop (quando closeOnBackdrop está habilitado) ou pressionando Escape. Ao fechar, o foco retorna ao elemento que originou a abertura.
Composição
Use mk-button com variant="filled" para a ação principal no mk-dialog-footer e variant="outlined" para cancelar. Para ações destrutivas, aplique kind="destructive" no botão de confirmação para reforçar o risco da operação ao usuário.
O mk-dialog-footer aplica automaticamente display: flex, justify-content: flex-end e gap entre os botões — não é necessário adicionar um elemento wrapper.
Props — mk-dialog
| Prop | Tipo | Padrão | Descrição |
|---|---|---|---|
open | boolean | false | Controla a visibilidade do dialog. |
size | "sm" | "md" | "lg" | "xl" | "md" | Controla o max-width do painel. |
closeOnBackdrop | boolean | true | Fecha o dialog ao clicar no backdrop. |
hideClose | boolean | false | Oculta o botão X do cabeçalho. |
heading | string | — | Atalho para título simples sem usar mk-dialog-header. Ignorado quando mk-dialog-header é fornecido. |
locale | string | — | Tag BCP 47 para i18n ("en", "pt-BR"). Recai para o lang do ancestral mais próximo. |
Eventos
| Evento | Payload | Descrição |
|---|---|---|
mkClose | void | Emitido ao fechar via botão X, clique no backdrop ou tecla Escape. |
Subcomponentes
| Tag | Slot atribuído | Descrição |
|---|---|---|
mk-dialog-header | header | Renderiza o conteúdo no cabeçalho do dialog. Atribui slot="header" automaticamente quando filho direto de mk-dialog. Aceita texto simples ou markup customizado. |
mk-dialog-body | (default) | Renderiza o conteúdo no corpo do dialog. Adiciona padding e tipografia padrão do corpo. |
mk-dialog-footer | footer | Renderiza o rodapé de ações. Atribui slot="footer" automaticamente quando filho direto de mk-dialog. Aplica flex, justify-content: flex-end e gap internamente. |
Acessibilidade
role="dialog"earia-modal="true"aplicados no painel.aria-labelledbyaponta para o conteúdo demk-dialog-headerquando presente, para que leitores de tela anunciem o contexto ao abrir.- Trap de foco ativo enquanto o dialog estiver aberto — Tab e Shift+Tab cicla entre elementos focáveis.
- Escape fecha o dialog e restaura o foco ao elemento que o abriu.
bodyrecebeoverflow: hiddenenquanto o dialog estiver aberto.
Trap de foco: enquanto o dialog estiver aberto, o Tab deve circular apenas pelos elementos dentro dele — o usuário não deve conseguir focar elementos da página ao fundo.
Overlay: o conteúdo ao fundo deve ser marcado como inerte (aria-hidden="true") enquanto o dialog estiver aberto, evitando que leitores de tela naveguem por ele.