Modal
Adapter React independente em que Ark UI fornece as parts e Zag mantém foco, teclado, estado e bloqueio do conteúdo externo.
Design
Anatomia
Review changes 4
Check the details before applying this update.
The update can be reverted later from the activity log.
6.ds-modal-overlay) — backdrop em tela cheia que bloqueia interação com a página.2 Container (
.ds-modal) — superfície elevada com border-radius e sombra.3 Header (
.ds-modal__header) — contém heading opcional, descrição e button de fechar.4 Título (
.ds-modal__title) — vinculado via aria-labelledby.5 Button de fechar (
.ds-modal__close) — dispensa o modal.6 Corpo (
.ds-modal__body) — área de conteúdo com scroll.7 Rodape (
.ds-modal__footer) — buttons de ação alinhados a direita.
Exemplo interativo · Ark/Zag
Executado pelo adapter independente Ark UI com comportamento Zag.
Tamanhos · Ark/Zag
Três dialogs independentes controlados pelas parts Ark UI e pelo comportamento Zag.
Body customizado · Ark/Zag
Composição real de campo e ações dentro do adapter Ark/Zag.
Mapeamento de tokens
| Propriedade | Token | Variável CSS |
|---|---|---|
| overlay background | component.modal.overlay.bg.default | --ds-modal-overlay-bg-default |
| surface | semantic.surface.elevated | --ds-surface-elevated |
| overlay padding | component.modal.overlay.padding.default | --ds-modal-overlay-padding-default |
| overlay z-index | component.modal.overlay.z-index.default | --ds-modal-overlay-z-index-default |
| border-radius | component.modal.radius.default | --ds-modal-radius-default |
| shadow | component.modal.shadow.default | --ds-modal-shadow-default |
| max-width | component.modal.max-width.{sm,md,lg} | --ds-modal-max-width-* |
| header spacing | component.modal.header.{padding-*,gap}.* | --ds-modal-header-*-* |
| body spacing/typography | component.modal.body.{padding-*,font-size,line-height,font-weight}.* | --ds-modal-body-*-* |
| description typography | component.modal.body.{font-size,line-height,font-weight}.* | --ds-modal-body-*-* |
| title typography | component.modal.title.{font-size,line-height,font-weight,letter-spacing}.* | --ds-modal-title-*-* |
| footer spacing | component.modal.footer.{padding-*,gap}.* | --ds-modal-footer-*-* |
| close target | component.modal.close.size.{sm,md,lg} | --ds-modal-close-size-* |
| close icon | component.modal.close.icon-size.{sm,md,lg} | --ds-modal-close-icon-size-* |
| close padding | component.modal.close.padding.{sm,md,lg} | --ds-modal-close-padding-* |
Uso
Quando usar
- Uma edição curta ou revisão precisa terminar antes de retornar ao contexto anterior.
- O conteúdo exige atenção concentrada, mas ainda não justifica uma página dedicada.
Quando não usar
- A tarefa é longa, possui várias etapas ou precisa continuar visível junto da página.
- A confirmação é destrutiva ou crítica; esse caso pertence ao contrato separado de Alert Dialog.
Quando escolher esta saída
Adote este adapter em projetos que escolheram Ark UI e Zag como arquitetura comportamental. Não o importe dentro da saída shadcn/Base UI.
Implementação
- Status
- Beta
- Distribuição
- Adapter de source
Source do adapter
packages/react/src/ark/modal.jsx
import {
Modal,
ModalBody,
ModalClose,
ModalContent,
ModalDescription,
ModalFooter,
ModalHeader,
ModalHeading,
ModalTitle,
ModalTrigger,
} from '@tis/react/ark/modal'Acessibilidade
Interação por teclado
| Tecla | Ação |
|---|---|
Tab | Cicla o foco dentro do modal (focus trap) |
Shift+Tab | Cicla o foco para tras dentro do modal |
Escape | Fecha o modal |
Enter | Ativa o button focado |
O foco deve ser preso dentro do modal enquanto estiver aberto. Quando o modal fechar, o foco deve retornar ao elemento que o disparou.
Accessibility
| Critério WCAG | Requisito | Status |
|---|---|---|
| 2.4.3 Focus Order (A) | O foco move para dentro do modal ao abrir, fica preso dentro e retorna ao trigger ao fechar | ✓ |
| 2.4.11 Focus Appearance (AA) | Focus ring visível em todos os elementos interativos dentro do modal | ✓ |
| 4.1.2 Name, Role, Value (A) | role="dialog", aria-modal="true", aria-labelledby apontando para o título | ✓ |
| 1.4.11 Non-text Contrast (AA) | Button de fechar tem pelo menos 3:1 de ratio de contraste contra a superfície do modal | ✓ |
role="dialog" — identifica o modal como um diálogo.aria-modal="true" — informa a tecnologia assistiva que o conteúdo atras do modal esta inerte.aria-labelledby — referencia o id do elemento de título do modal.aria-label="Close modal" — obrigatorio no button de fechar.
Responsabilidade da saída
Preserve a semântica Ark/Zag e valide Escape, interação externa, relações ARIA e retorno de foco.
Evidência de validação
Coberta pelo Storybook da saída independente e por verificações de browser, responsividade, teclado, Axe e bundle.