Filter Group
Em andamentoFileira de pílulas que filtram uma lista na hora. No modo único (padrão) é um grupo de rádio — uma marcada por vez, com as setas; no modo múltiplo, cada pílula alterna. A marcada fica em vermelho e com o visto. Rola na horizontal quando não cabe.
- Função
- Formulário e ação
- Também chamado de
- filtros, pílulas, chips, categorias, filtro rápido
- Mora em
- app/components/molecules/FilterGroup.tsx
- Última mudança
- 2026-09-30
Prévia
A peça ao vivo, vinda da ficha, na largura escolhida. Em larguras fixas, ela roda num quadro do tamanho de uma tela de verdade.
Na largura da página: 0px
Variantes na ficha
Lidas da ficha no build, na ordem do palco. Cada uma abre sozinha, sem o styleguide em volta — é o endereço que o palco carrega.
Quando usar
Acima de uma grade ou lista, para trocar entre recortes dela sem sair da página — áreas de curso, categorias do blog. O modo múltiplo, quando os recortes se somam ("Saúde" e "Gestão").
Faça
- Dê um
labelque diga o que se filtra ("Áreas do curso"): é o nome do grupo para o leitor. - Escolha o
modopela forma de escolha:unicoquando só um recorte vale por vez,multiploquando eles se somam — e aí oselectedé uma lista. - Deixe uma opção "Todos" como primeira, marcada por padrão, no modo único.
- Separe o que se mostra do que se filtra com
{ valor, rotulo }: "Negócios" pode filtrar pornegocios. - Use
contagemquando o número ajuda a escolher, edesabilitadopara o recorte vazio que ainda vale ver.
Evite
- Muitas opções: além de oito ou dez, a fileira vira rolagem que ninguém vê (a barra de rolagem é escondida).
- Usar para navegar entre páginas: é filtro, não menu.
- Modo único para recortes que se somam: a pessoa tenta marcar dois e perde o primeiro.
Quando não usar. Para alternar entre painéis de conteúdo, use o CourseTabs. Para muitos filtros combinados, o CourseFilterSidebar. Num formulário, para escolha única, o Radio.
Anatomia
As partes, na ordem em que o olho — e o teclado — passam.
- Grupo — Modo único: `role="radiogroup"`; múltiplo: `role="group"`. O `label` é o nome; rola na horizontal sem barra visível.
- Pílula — Um `<button>`: `role="radio"` com `aria-checked` no modo único, `aria-pressed` no múltiplo. Texto negrito `text-sm`, cantos redondos.
- Visto — Ícone `Check` de 16px antes do rótulo, só na marcada, com `aria-hidden` (o estado já vai no atributo).
- Contagem — Com `contagem`, o número depois do rótulo, em peso médio.
Estados
Os estados que a peça tem no código, e o que muda em cada um.
| Estado | O que muda |
|---|---|
| Marcada | Fundo e borda --primary, texto branco e o visto; aria-checked (ou aria-pressed) "true". |
| Não marcada | Fundo --card, texto --muted-foreground, borda de controle --border-interactive, sem visto. |
| Hover (não marcada) | Fundo --muted. |
| Foco | O anel de foco (anel-de-foco), só no teclado. |
| Desabilitada | A 50%, cursor proibido, fora do Tab e pulada pelas setas. |
Comportamento
| Situação | O que acontece |
|---|---|
| Escolher no modo único | Chama onSelect com o valor; quem guarda a escolhida é o consumidor (selected). Conferido no teste da ficha: a nova fica com aria-checked="true" e a anterior volta a false. |
| Com `contagem` | O número entra no nome, separado: "Todas, 42" — conferido no teste da ficha. |
| Escolher no modo múltiplo | Chama onSelect com a lista nova — a pílula entra ou sai dela. Conferido no teste da ficha. |
Relacionados
Como usar no código
A importação e o menor uso, lidos do arquivo. O … marca as props obrigatórias.
import { FilterGroup } from '@/app/components/molecules/FilterGroup';
<FilterGroup />Propriedades
Lidas do código da peça no build — não escritas à mão.
| Prop | Tipo | Padrão | Obrigatória | Descrição |
|---|
Aceita também: | (Base & { /** Uma opção por vez (padrão): grupo de rádio, com as setas. */ modo?: 'unico'; selected: string; onSelect: (valor: string) => void; }) | (Base & { /** Várias opções juntas: cada pílula alterna, com `aria-pressed`. */ modo: 'multiplo'; selected: string[]; onSelect: (valores: string[]) => void; }).
Medidas
| Parte | Valor | Classe |
|---|---|---|
| Altura da pílula | 44px (medido em 1280 e 375) | min-h-alvo-toque px-4 |
| Visto | 16px | Check size={16} |
Tokens de cor
Os tokens semânticos que o código da peça usa, com o valor de hoje em app/globals.css.
| Token | Valor | Usado como |
|---|---|---|
--primary | #D42B2B | bg-primaryborder-primary |
--border-interactive | #8C8C8C | border-border-interactive |
--card | #FFFFFF | bg-card |
--muted | #F4F6F9 | bg-muted |
--muted-foreground | #595959 | text-muted-foreground |
--primary-foreground | #FFFFFF | text-primary-foreground |
Teclado
| Tecla | Faz |
|---|---|
| Tab | Modo único: entra no grupo pela marcada (ou pela primeira) e sai dele no próximo Tab — uma parada só. Múltiplo: cada pílula é uma parada. Conferido no teste da ficha. |
| →↓ | Modo único: vai à próxima e a marca, pulando a desabilitada; da última volta à primeira. |
| ←↑ | Modo único: vai à anterior e a marca. |
| HomeEnd | Modo único: vai à primeira ou à última e a marca. |
| EnterEspaço | Marca a pílula em foco; no modo múltiplo, alterna. |
Leitor de tela
O que é anunciado, e por quê.
- O anúncio segue o comportamento (E61): no modo único, "botão de opção, marcado, 2 de 4"; no múltiplo, "botão alternado, pressionado". Antes toda pílula era alternância, e quem ouvia esperava poder desligar a do modo único.
- Estado nunca só por cor: a marcada ganha o visto além do vermelho.
O que sustenta o estado
Esta peça usa estatico. O estado dela é o de quem já foi ouvido com leitor de tela nesses padrões — e não uma passada sobre esta peça em específico.
Falta ouvir: estatico — ver docs/a11y-screen-reader-checklist.md.
Status e recursos
| Tipo | Recurso | Status |
|---|---|---|
| Código | app/components/molecules/FilterGroup.tsx | Disponível |
| Ficha | Storybook (abre em outra aba) | Disponível |
| Teste de acessibilidade | axe em npm run test | No gate de todo commit |
| Leitor de tela | Passada da E33 | Falta ouvir |
| Design | Figma | Desativado até a Fase 2 |
Histórico
Os últimos commits que tocaram o arquivo, lidos do git no build.
0298af82026-09-30E147: fechamento da Entrega 11 — REPORT.md, verificação cross-agent e o gate estático estrito
O histórico completo está no GitHub (abre em outra aba).