# CourseTabs

> Componentes / Navegação e estrutura · Estado: **Em andamento** — Implementado e utilizável, mas ainda sem a validação completa de acessibilidade.

Navegaçã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`
- Página: [https://phorte-design-system.vercel.app/styleguide/peca/CourseTabs](https://phorte-design-system.vercel.app/styleguide/peca/CourseTabs)
- Ficha no Storybook: [components-complex-coursetabs](https://main--69b4847d498a9bd8659db9ba.chromatic.com/?path=/docs/components-complex-coursetabs--docs)
- Prévia ao vivo, sozinha: [https://phorte-design-system.vercel.app/previa/CourseTabs/0](https://phorte-design-system.vercel.app/previa/CourseTabs/0)
- Todas as peças: [https://phorte-design-system.vercel.app/llms.txt](https://phorte-design-system.vercel.app/llms.txt)

## Como usar no código

```tsx
import { CourseTabs } from '@/app/components/molecules/CourseTabs';

<CourseTabs tabs={…} active={…}>…</CourseTabs>
```

O `…` marca as props obrigatórias — ver *Propriedades*.

## Uso

### Variantes na ficha

1. [Padrão](https://phorte-design-system.vercel.app/previa/CourseTabs/0)
2. [Interativo](https://phorte-design-system.vercel.app/previa/CourseTabs/1)
3. [Com ids](https://phorte-design-system.vercel.app/previa/CourseTabs/2)

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.

### 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.

### Faça

- Passe as seções como `{ id, rotulo }`: o `id` é a âncora e a chave, e o rótulo pode mudar sem quebrar nada (E71).
- Dê às seções da página os mesmos `id`s.
- Atualize `active` pela rolagem (ou pelo `onChange` do 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.

### Anatomia

1. **Navegação** — `<nav>` com o `label` ("Seções do curso"); lista com borda embaixo e rolagem horizontal escondida.
2. **Link** — `text-lg` em negrito, `href="#<id>"`, 44px de altura.
3. **Sublinhado** — Linha de 2px no vermelho de interface sob a atual, decorativa.

### Estados

| 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

- [Abas](https://phorte-design-system.vercel.app/styleguide/md/Abas.md) — Para trocar o conteúdo no lugar.
- [FilterGroup](https://phorte-design-system.vercel.app/styleguide/md/FilterGroup.md) — Para filtrar uma lista.
- [CurriculumAccordion](https://phorte-design-system.vercel.app/styleguide/md/CurriculumAccordion.md) — A grade curricular, que costuma vir numa das seções.

## Especificação

### Propriedades

| 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

| Token | Valor | Usado como |
| --- | --- | --- |
| `--primary` | #D42B2B | `bg-primary`, `text-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` |

## Acessibilidade

### 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

- 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

Usa os padrões: navegacao. Falta ouvir com leitor de tela: navegacao.

## Status e recursos

| Tipo | Recurso | Status |
| --- | --- | --- |
| Código | `app/components/molecules/CourseTabs.tsx` | Disponível |
| Ficha | https://main--69b4847d498a9bd8659db9ba.chromatic.com/?path=/docs/components-complex-coursetabs--docs | 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

- `0298af8` 2026-09-30 — E147: fechamento da Entrega 11 — REPORT.md, verificação cross-agent e o gate estático estrito
- Histórico completo no GitHub: https://github.com/srbunnie/Pos-Phorte-Design-System/commits/main/app/components/molecules/CourseTabs.tsx
