Filter
ProntoBarra de filtros aplicáveis a uma listagem. Combina chips removíveis (filtros aplicados) + popover de adicionar filtro.
Usar quando
Listas de processos, contatos, intimações com filtros multi-dimensão. Tabela com refinamento. Dashboard com slices de dados.
Não usar quando
Lista pequena (use search). Filtro único (use Select). Múltiplos filtros simples (use checkbox group inline).
Variantes
Microinterações
| Microinteração | Disparada por | Comportamento | Timing |
|---|---|---|---|
| Add chip | select no popover | Chip aparece com scale 0.85→1 | 200ms cubic-bezier(0.32,0.72,0,1) |
| Remove chip | click X | Chip diminui horizontal + opacity 1→0 | 200ms ease |
| Clear all | click "Limpar" | Todos chips desaparecem em cascata 50ms stagger | cumulativo |
| Quick filter toggle | click pill | Background ink ↔ surface, label inverte cor | 150ms ease |
| Counter pulse | filter aplicado muda result count | "X resultados" pisca brass 1x | 300ms |
Acessibilidade
Acessibilidade — checklist
Teclado
| Tab | Foco no botão "Adicionar filtro" |
| Enter / Space | Abre popover de filtros disponíveis |
| Backspace em foco no chip | Remove o filtro |
| Esc | Fecha popover sem aplicar |
ARIA esperado
- role="region" aria-label="Filtros aplicados"
- aria-live="polite" para anunciar filtros adicionados/removidos
- Cada chip: aria-label="Filtro área igual a Trabalhista, clique para remover"
- Botão limpar: aria-label="Limpar todos os filtros (5 aplicados)"
Notas
- Sempre exibe contador de resultados ao lado dos filtros.
- Chips removíveis com X visível.
- Em mobile: scroll horizontal dos chips com snap.
- Quick filters são toggles independentes (não selectivo).
Código
'use client';
import { Filter, X } from 'lucide-react';
import { T, SP, RADIUS } from '@/lib/tokens';
interface AppliedFilter { id: string; label: string; value: string }
export function FilterBar({ filters, onRemove, onAdd, onClear, count }: Props) {
return (
<div role="region" aria-label="Filtros aplicados" style={{ display: 'flex', alignItems: 'center', gap: SP[2], flexWrap: 'wrap' }}>
<button onClick={onAdd} style={{ /* botão "Adicionar filtro" */ }}>
<Filter size={12} /> Filtrar
</button>
{filters.map(f => (
<span key={f.id} style={{ /* chip */ }}>
<span>{f.label}: <strong>{f.value}</strong></span>
<button onClick={() => onRemove(f.id)}><X size={11} /></button>
</span>
))}
{filters.length > 0 && (
<>
<button onClick={onClear} style={{ /* link "Limpar" */ }}>Limpar</button>
<span>{count} resultado{count !== 1 ? 's' : ''}</span>
</>
)}
</div>
);
}Regras
Faça
- ✓Mostre filtros aplicados como chips removíveis.
- ✓Botão "Filtrar" abre popover ou modal pra adicionar.
- ✓Contador de resultados ao lado.
- ✓Botão "Limpar" remove todos.
- ✓Combine com URL params (?status=ativo) pra deep-link.
- ✓Quick filters (pills) para 3-5 filtros frequentes.
Não faça
- ✗Não esconda filtros aplicados em popover.
- ✗Não use checkbox solto (use chip removível).
- ✗Não esqueça de mostrar contagem.
- ✗Não force rerender sem indicador visual.
- ✗Não tenha mais de 8 quick filters lado-a-lado.
Tokens usados
| Token | Valor | Papel |
|---|---|---|
T.brassTint | rgba(164,124,43,0.08) | background dos chips |
T.ink | #0A0A0A | quick filter ativo |
T.surface3 | #F3F0E6 | quick filter inactive |
RADIUS.pill | 980 | chips e pills |