Badge
ProntoSelo curto e estático que comunica status, contagem ou categoria. Não-clicável (ao contrário de Chip).
Usar quando
Status de processo (Em andamento, Encerrado), contador de notificação, etiqueta de categoria, indicador de prazo.
Não usar quando
Ações clicáveis (use Chip ou Button). Texto longo (use parágrafo). Múltiplos badges competindo (escolha 1 protagonista).
Variantes
Microinterações
| Microinteração | Disparada por | Comportamento | Timing |
|---|---|---|---|
| Counter pop | count incrementa | Scale 1→1.2→1 do badge | 300ms cubic-bezier(0.32,0.72,0,1) |
| Dot pulse | variant=verde com dot (online) | Dot pulsa suavemente | 2s ease loop |
| Mount fade | componente entra | opacity 0→1 | 150ms ease |
Acessibilidade
Acessibilidade — checklist
ARIA esperado
- role="status" se badge informa estado dinâmico (ex: contador)
- aria-label="3 notificações novas" para counter
- Badges decorativos: nada (texto já é legível)
- Cor NUNCA é única indicação — texto/ícone sempre presente
Notas
- Counter > 99 → mostre "99+" para não estourar largura.
- Cor é sinal — vermelho só para urgente, verde só para positivo.
- NÃO use badge como botão — use Chip ou Button.
- Em badge inline com texto, mantenha contraste mínimo 4.5:1.
Código
'use client';
import { T, TYPE, RADIUS } from '@/lib/tokens';
interface BadgeProps {
children: React.ReactNode;
variant?: 'neutral' | 'brass' | 'carmim' | 'verde' | 'selo';
size?: 'sm' | 'md' | 'lg';
outline?: boolean;
dot?: boolean;
}
const VARIANT = {
neutral: { bg: T.surface3, fg: T.ink2, edge: T.border },
brass: { bg: T.brassTint, fg: T.brassLo, edge: T.brassEdge },
carmim: { bg: T.carmimTint, fg: T.carmim, edge: T.carmimEdge },
verde: { bg: T.verdeTint, fg: T.verde, edge: T.verdeEdge },
selo: { bg: T.seloTint, fg: T.selo, edge: T.seloEdge },
};
export function Badge({ children, variant = 'neutral', size = 'md', outline, dot }: BadgeProps) {
const v = VARIANT[variant];
return (
<span style={{
display: 'inline-flex', alignItems: 'center', gap: 4,
background: outline ? 'transparent' : v.bg,
color: v.fg,
border: outline ? `1px solid ${v.edge}` : 'none',
borderRadius: RADIUS.sm,
padding: size === 'sm' ? '2px 6px' : size === 'lg' ? '6px 12px' : '4px 8px',
fontSize: size === 'sm' ? 10 : size === 'lg' ? 13 : 11,
fontWeight: 500,
}}>
{dot && <span style={{ width: 6, height: 6, borderRadius: 980, background: v.fg }} />}
{children}
</span>
);
}Regras
Faça
- ✓Use cor por sinal: brass=ativo, carmim=urgente, verde=positivo, selo=info, neutral=default.
- ✓Counter > 99 → mostre "99+".
- ✓Tamanho sm para cabeçalho de tabela, md inline, lg em hero.
- ✓Outline para badges em fundos coloridos.
- ✓Dot semântico para status (online/busy/offline).
Não faça
- ✗Não use badge como botão.
- ✗Não use cor sem texto (a11y fail).
- ✗Não tenha 5+ badges na mesma área (caos visual).
- ✗Não use brass como decoração genérica.
- ✗Não force texto longo — badge é selo, não etiqueta longa.
Tokens usados
| Token | Valor | Papel |
|---|---|---|
T.brassTint | rgba(164,124,43,0.08) | background variant brass |
T.carmimTint | rgba(163,46,46,0.07) | background variant carmim |
T.verdeTint | rgba(47,107,60,0.07) | background variant verde |
T.seloTint | rgba(43,90,138,0.07) | background variant selo |
T.surface3 | #F3F0E6 | background variant neutral |
RADIUS.sm | 6 | borderRadius |
TYPE.xs | 11 | fontSize md |