Filter

Pronto

Barra 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

Barra de filtros aplicados (com chips removíveis)
Área: TrabalhistaStatus: Em andamentoResponsável: Paulo Batista91 resultados
Vazio (sem filtros aplicados)
247 resultados
Quick filters (toggle pills)

Microinterações

MicrointeraçãoDisparada porComportamentoTiming
Add chipselect no popoverChip aparece com scale 0.85→1200ms cubic-bezier(0.32,0.72,0,1)
Remove chipclick XChip diminui horizontal + opacity 1→0200ms ease
Clear allclick "Limpar"Todos chips desaparecem em cascata 50ms staggercumulativo
Quick filter toggleclick pillBackground ink ↔ surface, label inverte cor150ms ease
Counter pulsefilter aplicado muda result count"X resultados" pisca brass 1x300ms

Acessibilidade

Acessibilidade — checklist

Teclado
TabFoco no botão "Adicionar filtro"
Enter / SpaceAbre popover de filtros disponíveis
Backspace em foco no chipRemove o filtro
EscFecha 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

TokenValorPapel
T.brassTintrgba(164,124,43,0.08)background dos chips
T.ink#0A0A0Aquick filter ativo
T.surface3#F3F0E6quick filter inactive
RADIUS.pill980chips e pills