Modal
Dialog centralizado para decisões, confirmação e conteúdo que bloqueia o fluxo.
import { Button } from '@/components/ui/button'
import {
Dialog,
DialogClose,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from '@/components/ui/dialog'
export function DialogExample() {
return (
<Dialog>
<DialogTrigger asChild>
<Button variant="itps">Abrir modal</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Confirmar exclusão</DialogTitle>
<DialogDescription>Esta ação não pode ser desfeita.</DialogDescription>
</DialogHeader>
<p className="text-sm text-muted-foreground">
O paciente e todos os dados associados serão removidos permanentemente.
</p>
<DialogFooter>
<DialogClose asChild>
<Button variant="ghost">Cancelar</Button>
</DialogClose>
<Button variant="itps">Confirmar</Button>
</DialogFooter>
</DialogContent>
</Dialog>
)
} <script setup lang="ts">
import { Button } from '@/components/ui/button'
import {
Dialog,
DialogClose,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from '@/components/ui/dialog'
</script>
<template>
<Dialog>
<DialogTrigger as-child>
<Button variant="itps">Abrir modal</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Confirmar exclusão</DialogTitle>
<DialogDescription>Esta ação não pode ser desfeita.</DialogDescription>
</DialogHeader>
<p class="text-sm text-muted-foreground">
O paciente e todos os dados associados serão removidos permanentemente.
</p>
<DialogFooter>
<DialogClose as-child>
<Button variant="ghost">Cancelar</Button>
</DialogClose>
<Button variant="itps">Confirmar</Button>
</DialogFooter>
</DialogContent>
</Dialog>
</template> <button type="button" class="itps-btn itps-btn--primary" data-modal-open="confirm-modal">
Abrir modal
</button>
<dialog id="confirm-modal" class="itps-modal" aria-labelledby="confirm-modal-title" aria-describedby="confirm-modal-description" data-modal>
<header class="itps-modal__header">
<div class="itps-modal__heading">
<div class="itps-modal__copy">
<h2 id="confirm-modal-title" class="itps-modal__title">Confirmar exclusão</h2>
<p id="confirm-modal-description" class="itps-modal__description">Esta ação não pode ser desfeita.</p>
</div>
</div>
<button type="button" class="itps-modal__close" aria-label="Fechar" data-modal-close>
<i class="ti ti-x" aria-hidden="true"></i>
</button>
</header>
<div class="itps-modal__body">
<p>O paciente e todos os dados associados serão removidos permanentemente.</p>
</div>
<footer class="itps-modal__footer">
<button type="button" class="itps-btn itps-btn--ghost" data-modal-close>
<i class="ti ti-x" aria-hidden="true"></i>
<span>Cancelar</span>
</button>
<div class="itps-modal__footer-actions">
<button type="button" class="itps-btn itps-btn--primary">Confirmar</button>
</div>
</footer>
</dialog> Instalação
Instale Dialog e Button da sua stack e rode o comando individual ITpS em seguida. O comando itps add modal é theme-only: ele valida o slug e confirma que o contrato visual vem do tema ITpS, das classes copy-first e dos snippets desta página.
terminal · React/Next
pnpm dlx shadcn@latest add dialog button
pnpm dlx github:ITPS/sinapse-ui-cli add modal terminal · Vue3/Nuxt4
pnpm dlx shadcn-vue@latest add dialog button
pnpm dlx github:ITPS/sinapse-ui-cli add modal O comando individual adapta só este componente; não instala o catálogo inteiro.
Uso
Em React/Next com shadcn/ui e Vue3/Nuxt4 com shadcn-vue, use os compound components de Dialog. A stack gerencia foco, portal, ESC e acessibilidade.
Para HTML ou wrappers finos, use <dialog> nativo com itps-modal. No site, src/scripts/overlays.ts inicializa [data-modal], abre triggers com data-modal-open e fecha controles com data-modal-close.
Exemplos
Estrutura
| Peça | React/Next e Vue3/Nuxt4 | HTML |
|---|---|---|
| Raiz | Dialog | <dialog class="itps-modal" data-modal> |
| Trigger | DialogTrigger | [data-modal-open="id-do-modal"] |
| Cabeçalho | DialogHeader, DialogTitle, DialogDescription | itps-modal__header, aria-labelledby, aria-describedby |
| Ações | DialogFooter | itps-modal__footer |
| Fechar | DialogClose | itps-modal__close ou [data-modal-close] |
Status
Use alert quando a decisão pede atenção e error quando existe falha ou bloqueio.
<button type="button" class="itps-btn itps-btn--secondary" data-modal-open="alert-modal">
Modal alert
</button>
<dialog id="alert-modal" class="itps-modal itps-modal--alert" aria-labelledby="alert-modal-title" aria-describedby="alert-modal-description" data-modal>
<header class="itps-modal__header">
<div class="itps-modal__heading">
<span class="itps-modal__icon" aria-hidden="true">
<i class="ti ti-alert-triangle" aria-hidden="true"></i>
</span>
<div class="itps-modal__copy">
<h2 id="alert-modal-title" class="itps-modal__title">Sem conexão</h2>
<p id="alert-modal-description" class="itps-modal__description">Suas alterações foram salvas localmente.</p>
</div>
</div>
<button type="button" class="itps-modal__close" aria-label="Fechar" data-modal-close>
<i class="ti ti-x" aria-hidden="true"></i>
</button>
</header>
<div class="itps-modal__body">
<p>Confira a conexão antes de continuar o atendimento.</p>
</div>
<footer class="itps-modal__footer">
<button type="button" class="itps-btn itps-btn--primary" data-modal-close>Entendi</button>
</footer>
</dialog>
<button type="button" class="itps-btn itps-btn--secondary" data-modal-open="error-modal">
Modal error
</button>
<dialog id="error-modal" class="itps-modal itps-modal--error" aria-labelledby="error-modal-title" aria-describedby="error-modal-description" data-modal>
<header class="itps-modal__header">
<div class="itps-modal__heading">
<span class="itps-modal__icon" aria-hidden="true">
<i class="ti ti-alert-circle" aria-hidden="true"></i>
</span>
<div class="itps-modal__copy">
<h2 id="error-modal-title" class="itps-modal__title">Falha no upload</h2>
<p id="error-modal-description" class="itps-modal__description">O arquivo excede 10 MB.</p>
</div>
</div>
<button type="button" class="itps-modal__close" aria-label="Fechar" data-modal-close>
<i class="ti ti-x" aria-hidden="true"></i>
</button>
</header>
<div class="itps-modal__body">
<p>Escolha outro arquivo ou compacte o documento antes de tentar novamente.</p>
</div>
<footer class="itps-modal__footer">
<button type="button" class="itps-btn itps-btn--primary" data-modal-close>Tentar novamente</button>
</footer>
</dialog> API copy-first
| Classe/atributo | Uso |
|---|---|
itps-modal | Superfície visual do <dialog>. |
itps-modal--alert, itps-modal--error | Status visual para atenção e bloqueio. |
itps-modal__header, itps-modal__body, itps-modal__footer | Anatomia interna. |
itps-modal__close | Botão de fechamento com nome acessível. |
data-modal | Marca o dialog inicializável pelo script. |
data-modal-open, data-modal-close | Abre por id e fecha o dialog atual. |
aria-labelledby, aria-describedby | Conectam título e descrição ao dialog. |
aria-label | Nomeia o botão de fechar quando ele usa só ícone. |
Acessibilidade
Use modal para confirmação, decisão bloqueante ou tarefa curta. Para feedback transitório prefira Toast; para conteúdo longo prefira Side Panel; para informação sem bloqueio prefira Callout ou Banner.
No shadcn, preserve DialogTitle e DialogDescription. No copy-first, conecte título e descrição com aria-labelledby e aria-describedby, use botão real para fechar com aria-label="Fechar" e deixe o <dialog> nativo controlar ESC e modalização.