Course Tabs
Em andamentoNavegação entre as seções da página do curso — Apresentação, Matriz Curricular, Corpo Docente… —, por links âncora, com a seção atual em vermelho, sublinhada e marcada com aria-current="location" (E71).
- Função
- Navegação e estrutura
- Também chamado de
- seções do curso, menu da página do curso, âncoras, abas do curso
- Mora em
- app/components/molecules/CourseTabs.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
No topo da página de um curso, para pular entre as seções da mesma página, que ficam todas lá, uma embaixo da outra.
Faça
- Passe as seções como
{ id, rotulo }: oidé a âncora e a chave, e o rótulo pode mudar sem quebrar nada (E71). - Dê às seções da página os mesmos
ids. - Atualize
activepela rolagem (ou peloonChangedo clique), para a seção atual acompanhar a leitura.
Evite
- Usar para trocar conteúdo no lugar: aí é Abas.
- Rótulos repetidos com
string[]: o id sai do texto, e dois iguais colidem.
Quando não usar. Para trocar o conteúdo no lugar, sem rolar, use as Abas (contrato de abas inteiro). Para filtrar uma lista, o FilterGroup. Para seções curtas recolhíveis, o Accordion.
Anatomia
As partes, na ordem em que o olho — e o teclado — passam.
- Navegação — `<nav>` com o `label` ("Seções do curso"); lista com borda embaixo e rolagem horizontal escondida.
- Link — `text-lg` em negrito, `href="#<id>"`, 44px de altura.
- Sublinhado — Linha de 2px no vermelho de interface sob a atual, decorativa.
Estados
Os estados que a peça tem no código, e o que muda em cada um.
| Estado | O que muda |
|---|---|
| Atual | Texto --primary, sublinhado de 2px e aria-current="location". |
| Outra seção | Texto --muted-foreground; no hover, --ink. |
| Foco | Anel de 2px por dentro do link. |
Comportamento
| Situação | O que acontece |
|---|---|
| Escolher uma seção | Segue a âncora (a página rola até a seção) e chama onChange com o id; quem guarda a atual é o consumidor. Conferido no teste da ficha. |
| Com `string[]` | O id sai do texto sem acento: "Matriz Curricular" → #matriz-curricular; o onChange recebe o texto, como antes. |
| Fileira maior que a tela | Rola na horizontal, com encaixe por item (snap-x), sem barra visível. Quem rola é a lista, e não a página: a <nav> encolhe dentro de pai flex (E139 — a 320px a página rolava de lado), testado. |
Relacionados
Como usar no código
A importação e o menor uso, lidos do arquivo. O … marca as props obrigatórias.
import { CourseTabs } from '@/app/components/molecules/CourseTabs';
<CourseTabs tabs={…} active={…}>…</CourseTabs>Propriedades
Lidas do código da peça no build — não escritas à mão.
| Prop | Tipo | Padrão | Obrigatória | Descrição |
|---|---|---|---|---|
tabs | (string | SecaoDoCurso)[] | — | sim | As seções, na ordem da página. Com string, o id sai do texto ("Matriz Curricular" → matriz-curricular). |
active | string | — | sim | O id (ou o texto, com string[]) da seção em que a pessoa está. |
onChange | (id: string) => void | — | não | Chamado no clique, com o id — para quem acompanha a rolagem. |
label | string | 'Seções do curso' | não | Nome da navegação. |
Aceita também: Omit<React.HTMLAttributes<HTMLElement>, 'onChange'>.
Medidas
| Parte | Valor | Classe |
|---|---|---|
| Altura do link | 44px | min-h-alvo-toque |
| Sublinhado | 2px | h-0.5 |
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-primarytext-primary |
--border | #E5E5E5 | border-border |
--foreground | #1A1A1A | text-ink |
--muted-foreground | #595959 | text-muted-foreground |
--ring | var(--footer-red)), decisão da revisão 2. Se outra peça precisar
* dele como superfície, o nome vira de papel (ex.: --surface-brand-strong). */
--footer-red: #7D1B1B | ring-ring |
Teclado
| Tecla | Faz |
|---|---|
| Tab | Vai de link em link — cada seção é uma parada. Conferido no teste da ficha. |
| Enter | Segue a âncora e marca a seção como atual — conferido no teste da ficha. |
Leitor de tela
O que é anunciado, e por quê.
- Uma navegação de links, e não abas (E71, decisão com padrão): a peça rola até seções da mesma página, e as Abas já cobrem o trocar no lugar. A seção atual é anunciada como "local atual" (
aria-current="location"), e não só pela cor. - Até a E71 era um grupo de botões
aria-pressed— "botão alternar, pressionado", sem dizer que havia uma seção ligada.
O que sustenta o estado
Esta peça usa navegacao. 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: navegacao — ver docs/a11y-screen-reader-checklist.md.
Status e recursos
| Tipo | Recurso | Status |
|---|---|---|
| Código | app/components/molecules/CourseTabs.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).