Modelos e painéis de saída
1) Quando usar
Modal (diálogo com backdrop) - para soluções críticas e tarefas curtas que requerem atenção total: confirmação de ação, consentimento legal, operações perigosas, formulários curtos ≤ 1-2 campos. Bloqueia fundo.
Drawer/Sheet (painel de saída) - para extensão contextual: detalhes do objeto, edição de atributos, seleção da lista, navegação auxiliar. O fundo é visível → mantém o contexto.
- Se a ação precisar de concentração e confirmação do → Modal.
- Quando você deseja salvar o contexto e dar uma visão «paralela» do → Drawer.
2) Estrutura e tamanhos
Modal
O cabeçalho (obrigatório) → o texto principal → zona CTA (Primary/Segundary/Destrutive).
Dimensões: S (480-560 px), M (640-720 px), L (≤ 840 px). O telemóvel tem um sheet de tela cheia.
Drawer / Sheet
Direção: borda direita (desctop, edição), inferior (móbil, ações), às vezes esquerda (navegação).
Largura: 360-480 (S), 480-640 (M), 640-800 (L). No telemóvel, 90-100% de largura/altura.
A altura do conteúdo é sempre limitada, o interior é scroll; O título/CEM está fixo.
3) Copiatagem e CTA
Título = ação/significado: «Confirmar taxa», «Selecionar método de pagamento», «Necessário KYC».
O texto é breve, 1-2 frases. Evite fórmulas vagas.
CTA: 1 Primary, ao lado de Segundary («Cancelar») e, se necessário, Destrutive.
Para ações de risco, adicione uma explicação em 1 linha: "Ação irreversível. Você pode cancelar em 10 segundos (se estiver disponível)"
4) Comportamento e estado
Abertura: resposta instantânea ≤ 100 ms, seguida de animação 120-180 ms.
Fechando: mais rápido que a abertura (80-140 ms), voltando o foco para o desencadeador.
Busy: 'aria-busy =' true 'no contêiner, botão bloqueado de repetição.
Unsaved (forma suja): ao fechar, diálogo-aviso («Há alterações não salvas»).
Escape/clique sobre o fundo: Permitidos para diálogos não perigosos; para os críticos, apenas botões explícitos.
5) Disponibilidade (A11y)
Contêiner: 'role =' dialogog 'e' aria-modal = 'true' (para o verdadeiro modal).
O cabeçalho está ligado através de 'aria-labelledy'; descrição - 'ária-describedy'.
Focus trap dentro; o foco inicial é no cabeçalho ou no primeiro elemento interativo.
Devolve o foco ao desencadeador original após o fechamento.
Nada de scroll de fundo: body <overflow: hidden; 03 'ou' inert 'no resto do DOM.
O suporte ao teclado é Tab/Shift + Tab cíclico; Esc fecha (se não for proibido cenarmente).
Leve em conta 'preferers-reduced-motion': desabilite/simplifique animações.
html
<div class="backdrop" data-open hidden></div>
<div class="dialog" role="dialog" aria-modal="true" aria-labelledby="d-title" aria-describedby="d-desc" hidden>
<h2 id =" d-title "> Confirm Bid </h2>
<p id =" d-desc "> Sum of 200 ₴ by factor 1. 85</p>
<div class="actions">
<button class =" btn btn--primary "> Confirm </button>
<button class =" btn btn--ghost "> Cancel </button>
</div>
</div>
6) Performance e arquitetura
Render por meio do portal (camada acima do aplicativo) → menos problemas com o z-index.
Monta o conteúdo preguiçosamente na primeira abertura, desmonte depois da animação de encerramento (ou traduza offscreen).
Anime apenas 'transfm/opacity'; evite blur/sombras caros com grandes dimensões.
Bloqueie o scroll de fundo (scroll-lock) e mantenha a posição atual, para evitar que «salte» após o fechamento.
Para grandes listas em drawer - Use a virtualização.
7) Pattern móveis
Bottom sheet para ação/confirmação rápida: gestos de swipe para baixo para fechar (com limiar).
Sticky-CTA em baixo; o botão de fechamento é à esquerda.
Safe-area recuo (notch/gesture areas).
O teclado de tela não deve bloquear o CTA; layout - «levantar» conteúdo ou painel fixo acima do teclado.
8) Design Motion
Entrada: fade + mudança leve (modal: Y, drawer: eixo de aparência). 120-180 mc.
Saída: mais curto (80-140 ms), easing 'cubic-bezier (0. 2,0,0. 2,1)`.
Fundo (backdrop): opacidade 0 → 0. 4–0. 6. Sem pulsações ou blitzes infinitas.
Para 'preferers-reduced-motion': sem deslocamento, apenas fade.
9) Controle de fechamento
Encerramento imediato apenas em operações seguras.
Em caso de erro, permanecemos na janela e mostramos a razão e a Retry.
Em segundo plano, fechar a janela e mostrar o brinde «Executar no fundo»..., além da seção «Histórico».
10) Cenários típicos iGaming
10. 1 Confirmação de aposta (Modal)
Conteúdo: evento, coeficiente, soma, ganho potencial, validade do coeficiente.
Botões: Confirmar (primary), Cancelar.
Pattern atrasos> 3 c: texto «Aguardando confirmação»...; quando o coeficiente é alterado, é um update honesto.
10. 2 Cachaça (Modal/Sheet)
Exibe o valor atual do cachê e o timer da janela.
Confirmação + possível Undo (se o regulamento permitir).
10. 3 Escolha de método de pagamento (Drawer)
Lista de métodos com comissões/ETA; a escolha do → mini-formulário.
Salvar o método padrão; retorno sem perda de dados digitados.
10. 4 KYC (Drawer → Modal)
Drawer para carregar documentos/dicas.
Modal ao tentar fechar com download incompleto: alerta para não-salvos.
10. 5 Limites de Jogo Responsável (Modal)
Rádio «Dia/Semana/Mês», campo de valor, linha «Entrará em vigor através»....
11) Anti-pattern
Modais aninhados (modal acima do modal). Use uma única janela ou seqüência de passos.
Modalk para visualização normal de conteúdo (melhor drawer/página).
Uma cruz oculta ou um encerramento só por «microalgas».
Uma ação arriscada → permissão para fechar por um fundo.
Forma longa no modal (→ carregue para uma tela/painel separada).
Nenhum foco voltado para o desencadeador.
12) Sistema de design de tokens (exemplo)
json
{
"dialog": {
"radius": 12,
"shadow": "var(--elev-4)",
"sizes": { "s": 520, "m": 680, "l": 840 },
"backdropOpacity": 0. 5,
"padding": "20 24",
"gap": 16
},
"drawer": {
"width": { "s": 360, "m": 480, "l": 640 },
"edge": "right",
"radius": 12,
"shadow": "var(--elev-4)"
},
"motion": {
"inMs": 160,
"outMs": 120,
"ease": "cubic-bezier(0. 2,0,0. 2,1)",
"reduce": true
},
"a11y": {
"useAriaModal": true,
"focusTrap": true,
"returnFocus": true
}
}
Presetos CSS (conceito):
css
.backdrop[data-open]{position:fixed; inset:0; background:rgba(0,0,0,.5); backdrop-filter:saturate(80%); opacity:1; transition:opacity. 16s}
.dialog,[data-drawer]{position:fixed; background:var(--bg-elevated); border-radius:12px; box-shadow:var(--elev-4);}
.dialog{inset:auto; left:50%;top:50%;transform:translate(-50%,-50%); max-width:840px; width:min(100% - 32px, var(--dialog-w,680px));}
[data-drawer="right"]{top:0; right:0; height:100%;width:var(--drawer-w,480px); transform:translateX(0)}
.dialog[hidden],.backdrop[hidden]{display:none}
13) Snippets de comportamento
Focus trap + foco de retorno:js const openBtn = document. getElementById('open');
const dlg = document. querySelector('.dialog');
let prevFocus;
function openDialog() {
prevFocus = document. activeElement;
dlg. hidden = false; document. body. style. overflow = 'hidden';
const focusable = dlg. querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');
(focusable[0] dlg). focus();
function onKey(e){
if(e. key==='Escape') return closeDialog();
if(e. key!=='Tab') return;
const first = focusable[0], last = focusable[focusable. length-1];
if(e. shiftKey && document. activeElement===first){ e. preventDefault(); last. focus(); }
else if(!e.shiftKey && document. activeElement===last){ e. preventDefault(); first. focus(); }
}
dlg. addEventListener('keydown', onKey);
dlg. dataset. off = ()=> dlg. removeEventListener('keydown', onKey);
}
function closeDialog() {
dlg. dataset. off && dlg. dataset. off();
dlg. hidden = true; document. body. style. overflow = '';
prevFocus && prevFocus. focus();
}
Sheet com um gesto de fechamento (móbil, simplificado):
js let startY=0, delta=0;
const sheet = document. querySelector('.sheet');
sheet. addEventListener('touchstart', e => startY = e. touches[0].clientY);
sheet. addEventListener('touchmove', e => {
delta = Math. max(0, e. touches[0].clientY - startY);
sheet. style. transform = `translateY(${delta}px)`;
});
sheet. addEventListener('touchend', () => {
if (delta > 120) sheet. classList. remove('open'); else sheet. style. transform = '';
delta = 0;
});
14) Métricas e experiências
Open Rate/Complition Rate em modais: Quantos abrimos e terminamos.
Time-to-Decision: da abertura ao clique Primary.
Dismiss Rate e razões (encerrado por Esc/Fon vs «Cancelamento»).
Erro/Retry Rate em cenários busy.
A/B: modal vs drawer, texto CTA, ordem de campos, «confirmação» vs «undo».
15) QA-folha de cheque
Disponibilidade
- 'role =' dialogog ',' aria-modal = 'true', 'ária-labelledy/-describedy'.
- O Focus trap funciona; O truque volta ao desencadeador.
- Esc fecha (se permitido); O Tab é cíclico.
- Contraste ≥ AA; Não é só a cor que transmite o significado.
Comportamento
- TTFF ≤ 100 ms; animação in 120-180 mc/out 80-140 mc.
- Scroll-lock fundo sem «salto» de página.
- Unsaved-guard em forma suja.
- Estado Busy, Retry correto/erro.
Interface
- Título claro e um Primary-CTA.
- Cruzado/botão Fechar estão disponíveis.
- As dimensões são adaptáveis; No telemóvel, um sheet com um gesto.
Performance
- Os portais/z-index são corretos; sem «deslumbrar».
- Inicialização preguiçosa; Só são animados como transfm/opacity.
16) Documentação em design
Componentes: 'Modal', 'Drawer/Sheet', 'ConfirmDialog', 'UnsavedGuard'.
Tokens: dimensões, recuos, sombras, animações, backdrop, focus-ring.
Guedes: «Quando modal vs drawer», modelos de copiramento, ações de risco (confirm/undo), scroll-lock e portals, reduse-motion.
Do/Don 't galeria: nested modals (don' t), longas formas no modal (don 't), sheet para ampliar o contexto (do).
Resumo curto
Modalka - para soluções de atenção total, drawer - para ampliar o contexto sem quebrar o fluxo. Mantenha a estrutura simples, CTA inequívoca e as interações previsíveis e acessíveis. Respeite a performance, bloqueie o fundo e volte o foco. Nos cenários, isso afeta diretamente a confiança: confirmação de apostas, cachê, escolha de método de pagamento e KYC devem ser honestos, rápidos e seguros.