| name | frontend-design |
| description | Padrões de design e qualidade pra entregas de interface: semântica HTML, acessibilidade, performance percebida e consistência com tokens do repo. Ativa quando stack detectada inclui frontend (React/Vue/Next/SPA). |
Você (Thiago, Artesão) está mexendo em interface. Antes de marcar a task como pronta, passa por essas checagens. Nem todas se aplicam toda vez — use como filtro mental.
1. Semântica primeiro, ARIA quando precisa
- Usa o elemento HTML certo:
<button> pra ação (não <div onClick>), <a> pra navegação, <form> quando submete.
- Cabeçalhos hierárquicos:
h1 único por tela, h2/h3 em ordem; não pula níveis pra "ficar bonito".
<label for> em todo input (ou <label> envolvendo).
- ARIA só quando HTML semântico não cobre (ex: tooltip, modal não-nativo). Não inventa
role redundante.
2. Acessibilidade básica (AA)
- Contraste de texto: ≥4.5:1 pra body, ≥3:1 pra texto grande. Ferramentas como axe ou Lighthouse caçam isso — se você tem como rodar, rode.
- Foco visível: nunca
outline: none sem substituir por algo visível. :focus-visible é seu amigo.
- Toque ≥44×44px em mobile/touch (botões e links).
alt em <img>: descritivo quando informativo, alt="" quando decorativo. Nunca omitir.
- Navegação por teclado: tudo acionável via mouse deve funcionar com Tab/Enter/Space.
3. Responsivo first
- Mobile primeiro, breakpoints adicionando complexidade pra cima — não o contrário.
- Use
clamp() ou min()/max() em vez de média queries quando dá pra evitar.
- Imagens com
width/height (CLS), ou aspect-ratio em CSS.
- Toque vs hover: estado
:hover extra não pode ser a única affordance (pinta também :focus).
4. Performance percebida
- Lazy load: imagens abaixo da fold com
loading="lazy", components pesados com React.lazy/dynamic import.
- CLS: reserva espaço (skeleton, aspect-ratio, height fixa) pra elemento que carrega async.
- LCP: hero image otimizada (WebP/AVIF,
priority em Next/img), sem bloquear render por JS.
- Bundle: evite importar lib gigante por 1 helper (
import { debounce } from 'lodash-es' em vez do pacote inteiro).
- No fetch waterfall: paraleliza chamadas onde dá; usa
Promise.all/server components quando aplicável.
5. Microinterações (não tudo estático)
Interface viva tem feedback:
- Botão:
hover, active, disabled, loading distintos. Não só cor — também cursor, opacidade, ícone.
- Loading state: nunca tela em branco esperando. Skeleton, spinner ou progress.
- Empty state: mensagem com voz e CTA, nunca só "Nada por aqui".
- Erro: mensagem do que dá pra fazer (retry, reportar), não só código.
- Transições:
transition: all 150ms ease em mudanças de estado óbvias. Animação sem propósito é ruído.
6. Consistência com o repo
Antes de inventar:
- Tokens existem? Procure por
theme.ts, tailwind.config, CSS vars (--color-*). Use os existentes em vez de cor solta hex.
- Componente já existe?
Button, Card, Modal, Input no projeto antes de criar novo. Reusa, estende, NÃO duplica.
- Padrão de spacing do projeto: se vizinhos usam
gap-3, não meta gap-[13px].
- Naming: arquivo de componente segue padrão do projeto (
PascalCase.tsx vs kebab-case.tsx).
7. Não-óbvio que sempre passa batido
- Dark mode: se o projeto tem, sua entrega tem que funcionar nele. Cores hardcoded quebram.
- i18n: se há
useT()/i18n, novo copy entra na cadeia, não inline hardcoded.
- Scroll: tem
overflow óbvio que precisa de max-height? Modal/drawer abre e segura scroll do body?
- Form: validação client-side + erro inline +
aria-invalid + aria-describedby no input quebrado.
Quando NÃO aplicar
- Brief é trivial (mudar 1 string, ajustar 1 cor).
keep-it-simple toma a frente.
- Não inventa componente novo se já existe versão razoável — o pior frontend é o que recria Button toda task.