UI e responsividade¶
Duas regras mandam aqui, e as duas vêm do que foi combinado com a cliente: ✅
- Responsivo não é caso especial. A plataforma é usada no celular e no desktop. Componente que só funciona no desktop está incompleto, não pronto.
- A biblioteca é fechada. O que está no
package.jsonresolve. Pacote novo de UI é decisão do time, não do componente da vez.
O que já existe — use¶
| Para | Use | Onde |
|---|---|---|
| Primitivos de UI | shadcn/ui (estilo radix-nova, base neutral) |
src/components/ui/ |
| Ícones | lucide-react |
— |
| Variantes de um componente | class-variance-authority (cva) |
ver src/components/ui/button.tsx |
| Juntar classes | cn() de @/lib/utils |
sempre — nunca template string crua |
| Formulário | react-hook-form + zod |
Formulários |
| Animação | tw-animate-css e as transições do Tailwind |
— |
| Gráfico | recharts |
já instalado, ainda sem uso no código |
| Texto visível | react-i18next (useTranslation) |
src/i18n/locales/ |
| Teste | Vitest + Testing Library + user-event |
src/test/setup.ts |
Detalhes que passam despercebidos:
- Tailwind é v4, configurado em CSS. Os tokens ficam em
@theme, dentro desrc/index.css. Não existetailwind.config.js— não crie um. - A ordem das classes é automática: o
prettier-plugin-tailwindcssordena. - Cor sai dos tokens do tema (
bg-background,text-foreground,bg-primary…), nunca hex no componente — nem no hover. A identidade visual muda num lugar só.
Precisa de algo que não existe?¶
| Situação | O que fazer |
|---|---|
Primitivo que o shadcn tem e o projeto ainda não instalou (sheet, tabs, dropdown-menu…) |
npx shadcn@latest add <nome> — mesma registry, não é dependência nova |
| Variação visual de um componente existente | uma variante nova com cva, no próprio componente |
| Ícone que falta | procure no lucide-react |
Pacote de UI fora dessa lista (outro kit, carrossel, framer-motion, date picker externo…) |
pare: é dependência nova. Justifique no PR e combine com o time antes |
"Seria mais bonito" e "eu já usei em outro projeto" não justificam pacote novo.
Responsividade¶
- Mobile-first. A base do
classNameé a tela pequena;sm:,md:,lg:sobem a partir dela. - Breakpoints do Tailwind, sem inventar:
sm640 ·md768 ·lg1024 ·xl1280. - Sem largura fixa em container:
w-full+max-w-*,flexougrid. - Sem rolagem horizontal na página. Conteúdo largo rola dentro do próprio
container:
overflow-x-auto. - Alvo de toque de pelo menos ~40px de altura no celular. Os tamanhos padrão do shadcn já atendem; não reduza.
- Confira em três larguras: 375, 768 e 1280. O teste automatizado não cobre isso — o jsdom não faz layout. É verificação sua, no navegador, e entra no "Como verificar" do PR.
Movimento¶
Movimento tem função — mostrar para onde a pessoa foi, confirmar um toque — e nunca é enfeite.
| Regra | Por quê |
|---|---|
| O que se repete é curto (~300ms); o que aparece uma vez pode ir a 500–700ms | a décima troca de pergunta com 500ms já cansa |
| Avançar entra pela direita, voltar pela esquerda, tela nova entra de baixo | a pessoa sabe para onde foi sem ler nada |
| Só anima o que mudou | animar o que ficou igual é ruído |
Sempre motion-reduce:animate-none |
quem pediu menos movimento ao sistema não vê nenhum |
Modais¶
| Tipo | Componente | Comportamento |
|---|---|---|
| Comum (informação, contato) | Dialog |
fecha clicando fora ou com Esc |
| Obrigatório (a pessoa precisa escolher) | AlertDialog |
nem clique fora nem Esc fecham; os botões dizem a ação ("Revisar dados"), não "Sim" e "Não" |
Antes de dar o componente por pronto¶
- Ele já não existe? Procure antes de criar — componente duplicado é o erro mais comum.
- Mora no lugar certo: uma feature só → dentro dela; mais de uma →
src/components/; primitivo →src/components/ui/, pelo CLI do shadcn. - Nenhum texto escrito direto: tudo em
src/i18n/locales/, em todos os idiomas. - Nenhuma cor fora dos tokens do tema.
- Animação com
motion-reduce:animate-none. - Conferido em 375, 768 e 1280.
- Teste ao lado do componente.
-
npm run checkverde.