Componentes
30. Modal
seed-componentes.md v1.43 · §30seção 32 de 9830-modal-estavel-v0-30-md1-md5-validacao-executada.md · MD5 ae3c1d11Título completo no canon: Modal — estável (v0.30) · MD1–MD5 · validação executada 230/230 + visual aprovada em 2026-08-05 (1 ciclo de crítica)
Base (3 rodadas, 2026-08-05): R1 — APG dialog (trap, foco inicial: título tabindex=-1 quando conteúdo longo; alertdialog; exemplo oficial usa 100% da tela no mobile), NN/g ("diálogos curtos e diretos; nunca quando a decisão depende de informação bloqueada"), Smashing decision tree 2026 (evite bloquear; drawer antes de modal), MoJ/GOV.UK (GOV.UK não tem modal no DS; MoJ adotou p/ usuários profissionais com foco no 1º campo, validado em pesquisa). R2 — MDN showModal/::backdrop (primárias: Baseline "widely available" mar/2022; top layer; inert automático; retorno de foco nativo), Radix Dialog (stack), artigo top-layer (LIFO). R3 — Scott O'Hara "Use the dialog element (reasonably)" (primária: o autor do veto de 2019 liberou o nativo), accessuse.eu, CSUN 2019 (foco inicial).
30.1 Decisões MD1–MD5#
| # | Decisão | Porquê | Descartado |
|---|---|---|---|
| MD1 | Base: <dialog> nativo + showModal(); React = Radix Dialog (Lovable). Top layer (fim do z-index), ::backdrop, fundo inert (teclado E leitor), Esc e retorno de foco de graça. role="alertdialog" p/ confirmação destrutiva/erro bloqueante |
O'Hara liberou o nativo (2023); MDN Baseline desde mar/2022 | div+ARIA custom (custo sem ganho hoje); show() p/ modal ("modal quebrado": sem trap/backdrop/inert) |
| MD2 | Régua fecha os 3 degraus (§23.1): modal SÓ p/ decisão obrigatória, confirmação destrutiva ou tarefa curta e focada. Regra inversa: tarefa longa ou que exige consultar a página → drawer ou página | NN/g; Smashing 2026; GOV.UK nem tem modal (sinal de parcimônia) | Modal como contêiner conveniente (treina fechar por reflexo) |
| MD3 | Esc + X visível sempre; backdrop fecha SÓ modal sem formulário (com form: não — perda de dados); foco inicial: 1º campo em form (MoJ) · título tabindex="-1" se conteúdo longo (APG) · botão NÃO-destrutivo em confirmação destrutiva (APG); retorno ao trigger nativo; nome via aria-labelledby obrigatório |
APG + MoJ + accessuse.eu | Fechar só no X; foco inicial no botão destrutivo |
| MD4 | Tamanhos sm (confirmação) / md (form curto) com max-height + scroll no body; <640px modal de tarefa ocupa a tela (APG: esconde movimento de fundo do mobile); confirmações seguem centradas. Empilhamento proibido — 1 por vez; exceção única: confirmação de descarte sobre form sujo (replace, não pilha) | APG example; top layer é LIFO mas pilha quebra contexto/AT | Pilha de modais |
| MD5 | 3 zonas: header fixo (título+X) · body scrollável · footer fixo (ações). Tudo dentro herda: form→B2, espera→§18/§19, erro→§15, ações→B1. Nenhum componente nasce dentro do modal | EUI (pinned header/footer) | Modal com anatomia própria |
30.2 Tokens#
Superfície --seed-surface-overlay + --seed-shadow-overlay (pares §2.8/§17 já medidos) · radius 12 (herda card) · backdrop rgba(36,46,52,.5) light / rgba(0,0,0,.6) dark — DECORATIVO declarado (a separação modal↔página é dada por inert+trap+sombra+deslocamento; o escurecimento é reforço, nunca canal único) · animação 160ms ease-out com prefers-reduced-motion desligando. Nenhum par de texto novo.
30.3 Os 7 testes#
- Pares reusados ✓; backdrop decorativo declarado. 2. Modalidade sinalizada por trap+inert+sombra, não só escurecimento. 3. Grayscale ✓ (sombra+borda de zona carregam). 4. Confirmação × tarefa a 1s (sm centrado × zonas com form). 5. Um modal por vez (MD4). 6. Aberto é auto-evidente. 7. 360px: tarefa em tela cheia, X de 44px, footer acessível ao polegar. (Validação executada 230/230 + visual aprovada em 2026-08-05.)
Também cita o §30: banco-cn, banco-navegacao, tela-detalhe.