# Tabela

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

Dado em linhas e colunas: a grade de um curso, a carga horária por módulo, a lista de inscritos de uma turma. A legenda é obrigatória e dá nome à tabela; o cabeçalho que ordena é um botão; a tabela larga rola dentro da própria caixa.

- Função: Conteúdo
- Também chamado de: table, tabela de dados, grade, data table, lista de inscritos
- Mora em: `app/components/molecules/Tabela.tsx`
- Página: [https://phorte-design-system.vercel.app/styleguide/peca/Tabela](https://phorte-design-system.vercel.app/styleguide/peca/Tabela)
- Ficha no Storybook: [components-complex-tabela](https://main--69b4847d498a9bd8659db9ba.chromatic.com/?path=/docs/components-complex-tabela--docs)
- Prévia ao vivo, sozinha: [https://phorte-design-system.vercel.app/previa/Tabela/0](https://phorte-design-system.vercel.app/previa/Tabela/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 { Tabela } from '@/app/components/molecules/Tabela';

<Tabela legenda={…} colunas={…} linhas={…}>…</Tabela>
```

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

## Uso

### Variantes na ficha

1. [Padrão](https://phorte-design-system.vercel.app/previa/Tabela/0)
2. [Ordenada](https://phorte-design-system.vercel.app/previa/Tabela/1)
3. [Compacta](https://phorte-design-system.vercel.app/previa/Tabela/2)
4. [Com estado](https://phorte-design-system.vercel.app/previa/Tabela/3)
5. [Vazia](https://phorte-design-system.vercel.app/previa/Tabela/4)
6. [Larga](https://phorte-design-system.vercel.app/previa/Tabela/5)

Quando a pessoa compara valores entre linhas pela mesma coluna: carga horária, datas, situação de inscrição, notas.

### Quando não usar

Para comparar planos lado a lado, com preço e chamada: os cartões do PricingCards. Para uma lista de itens com ação em cada um (cursos, eventos): cartões. Para diagramar a página: nunca — tabela é dado, não grade de layout.

### Faça

- Escreva uma `legenda` que diga de quê é a tabela ("Grade do MBA em Fisiologia do Exercício"); com o título da seção dizendo o mesmo, `legendaOculta`.
- Marque o `cabecalhoDaLinha`: a coluna que nomeia a linha (o módulo, a pessoa) vira `<th scope="row">`, e o leitor diz o nome junto de cada valor.
- Número, preço e carga horária com `alinhamento: "fim"`: alinhados à direita, com algarismos de mesma largura.
- Célula com Badge ou link e coluna ordenável: passe `valorParaOrdenar`, para comparar o valor e não o desenho.
- Numa página de servidor (Server Component), não passe função (`chaveDaLinha`, `valorParaOrdenar`): a Tabela é de cliente, e o Next não serializa função. Sem elas, a tabela funciona; com elas, monte-a num componente de cliente (achado da E120).

### Evite

- Tabela para o que tem uma coluna só: é uma lista.
- Ordenar tudo: só a coluna em que a ordem ajuda a decidir.
- Estado só por cor na célula: use o Badge, que tem texto.

### Anatomia

1. **Legenda** — O `<caption>`: nome da tabela e da região que rola. Visível por padrão, em negrito.
2. **Cabeçalho** — Rótulos em 12px, caixa alta, `--muted-foreground`; o ordenável é um botão com o ícone da ordem.
3. **Linhas** — Separadas por `--border`; listradas em `--muted` por padrão. A primeira coluna pode ser o cabeçalho da linha, em semibold.
4. **Caixa** — Borda e raio da superfície; rola na horizontal quando a tabela não cabe.

### Estados

| Estado | O que muda |
| --- | --- |
| Sem ordem | O ordenável mostra as duas setas pequenas. |
| Ordenada | A coluna mostra a seta da direção, o rótulo em `--ink` e `aria-sort` no cabeçalho. |
| Vazia | Uma linha com a `mensagemVazia`, centralizada, ocupando todas as colunas. |
| Rolável | A caixa entra no Tab e mostra o anel de foco; sem transbordar, não entra. |

### Comportamento

| Situação | O que acontece |
| --- | --- |
| Clique ou Enter num cabeçalho ordenável | Ordena crescente; de novo, decrescente. A troca é anunciada ("Ordenado por Carga horária, crescente") — testado na ficha. |
| Ordenação controlada | Com `ordenacao`, a tabela mostra a ordem que recebe e só avisa por `onOrdenar`: quem ordena é quem chama (no servidor, por exemplo). |
| Tabela mais larga que a caixa | Rola dentro dela; a caixa vira parada de Tab e rola pelas setas — testado na ficha. |

### Relacionados

- [PricingCards](https://phorte-design-system.vercel.app/styleguide/md/PricingCards.md) — Comparar planos, com preço e chamada.
- [Badge](https://phorte-design-system.vercel.app/styleguide/md/Badge.md) — Estado dentro de uma célula, com texto.
- [Pagination](https://phorte-design-system.vercel.app/styleguide/md/Pagination.md) — Tabela longa, em páginas.

## Especificação

### Propriedades

| Prop | Tipo | Padrão | Obrigatória | Descrição |
| --- | --- | --- | --- | --- |
| `densidade` | `'padrao' \| 'compacta'` | `'padrao'` | não | Variante do `cva`. |
| `legenda` | `string` | — | sim | Obrigatória: é o `<caption>`, o nome da tabela e da região que rola. Sem ele, quem usa leitor de tela ouve "tabela, 4 colunas" e não sabe de quê. |
| `legendaOculta` | `boolean` | `false` | não | Esconde a legenda da tela (continua para o leitor). Use quando o título da seção já diz o mesmo. |
| `colunas` | `ColunaDaTabela[]` | — | sim |  |
| `linhas` | `LinhaDaTabela[]` | — | sim |  |
| `chaveDaLinha` | `(linha: LinhaDaTabela, indice: number) => string` | — | não | A chave de cada linha para o React. Sem ela, a posição — que muda ao ordenar. |
| `cabecalhoDaLinha` | `string` | — | não | A coluna que dá nome à linha (o curso, a turma): vira `<th scope="row">`. |
| `listrada` | `boolean` | `true` | não | Linhas alternadas em `--muted` (padrão). |
| `ordenacao` | `OrdenacaoDaTabela \| null` | — | não | Ordenação controlada. Sem ela, a tabela ordena sozinha a partir de `ordenacaoInicial`. |
| `ordenacaoInicial` | `OrdenacaoDaTabela \| null` | `null` | não |  |
| `onOrdenar` | `(ordenacao: OrdenacaoDaTabela) => void` | — | não | Chamado a cada clique num cabeçalho ordenável, com a ordenação nova. |
| `mensagemVazia` | `React.ReactNode` | `'Nada para mostrar.'` | não | O que aparece no corpo quando não há linha. |

Aceita também: `Omit<React.HTMLAttributes<HTMLDivElement>, 'children'>`.

### Tokens de cor

| Token | Valor | Usado como |
| --- | --- | --- |
| `--border` | #E5E5E5 | `border-border` |
| `--card` | #FFFFFF | `bg-card` |
| `--foreground` | #1A1A1A | `text-ink` |
| `--muted` | #F4F6F9 | `bg-muted` |
| `--muted-foreground` | #595959 | `text-muted-foreground` |

## Acessibilidade

### Teclado

| Tecla | Faz |
| --- | --- |
| Tab | Entra na caixa, se ela rola, e passa pelos botões de ordenar do cabeçalho. |
| Enter / Espaço | No cabeçalho, ordena pela coluna; de novo, inverte. |
| ← / → | Com a caixa em foco, rola a tabela na horizontal. |

### Leitor de tela

- A legenda nomeia a tabela e a região que rola: "Grade do MBA…, tabela".
- Com `cabecalhoDaLinha`, cada valor é lido com o nome da linha e o da coluna.
- A ordem está no `aria-sort` do cabeçalho, e a troca é dita uma vez numa região viva.

### O que sustenta o estado

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

## Status e recursos

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