# Accordion

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

Lista de seções recolhíveis: cada título é um botão dentro de um cabeçalho que abre e fecha o conteúdo abaixo. Uma aberta por vez, ou várias com `allowMultiple`, em tema claro ou escuro; pode abrir já num item e ser controlada de fora.

- Função: Conteúdo
- Também chamado de: sanfona, acordeão, recolhível, expansível, accordion
- Mora em: `app/components/molecules/Accordion.tsx`
- Página: [https://phorte-design-system.vercel.app/styleguide/peca/Accordion](https://phorte-design-system.vercel.app/styleguide/peca/Accordion)
- Ficha no Storybook: [components-complex-accordion](https://main--69b4847d498a9bd8659db9ba.chromatic.com/?path=/docs/components-complex-accordion--docs)
- Prévia ao vivo, sozinha: [https://phorte-design-system.vercel.app/previa/Accordion/0](https://phorte-design-system.vercel.app/previa/Accordion/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 Accordion from '@/app/components/molecules/Accordion';

<Accordion items={…}>…</Accordion>
```

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

## Uso

### Variantes na ficha

1. [Padrão](https://phorte-design-system.vercel.app/previa/Accordion/0)
2. [Permite Varias](https://phorte-design-system.vercel.app/previa/Accordion/1)
3. [Conteúdo próprio](https://phorte-design-system.vercel.app/previa/Accordion/2)
4. [Tema escuro](https://phorte-design-system.vercel.app/previa/Accordion/3)
5. [Aberto de início](https://phorte-design-system.vercel.app/previa/Accordion/4)

Para perguntas e conteúdos longos que não precisam aparecer todos de uma vez — módulos de um curso, regras de uma bolsa.

### Quando não usar

Para perguntas frequentes com título de seção e botão "ver todas", use o FAQ (que já usa o Accordion). Para a grade curricular, o CurriculumAccordion. Para alternar seções longas, o CourseTabs.

### Faça

- Escreva cada título como a pergunta ou o assunto inteiro — é o nome do botão.
- Acerte `nivelDoTitulo` pela página (padrão 3): é por ele que quem usa leitor pula de item em item pela tecla H.
- Use `allowMultiple` quando a pessoa precisar comparar dois itens abertos.
- Use `tema="escuro"` sobre fundo escuro: o anel de foco passa a ser o claro, e o subtítulo, claro (E65).
- Abra no máximo um de início, com `defaultOpenIds` — a grade no módulo atual (E65).
- Use `openIds` e `onOpenChange` para abrir por fora: um link direto para uma pergunta.

### Evite

- Esconder no acordeão a informação que quase todos precisam: o que é essencial fica à vista.
- Vários itens abertos de saída: vira uma página comprida sem o índice que o acordeão prometia.
- Um item só: sem outros, é só um botão de "mostrar mais".

### Nota de uso

**Teclado (E65):** Enter e Espaço abrem e fecham; o Tab entra no painel **aberto** (decisão local, para o texto revelado entrar no caminho) e segue para o próximo item. Não esconda aqui o que é essencial, e abra no máximo um de início (`defaultOpenIds`). Para abrir por fora — um link direto para uma pergunta —, `openIds` e `onOpenChange`. Ganhou `aria-expanded` e `aria-controls` na E08b — antes, quem ouvia não sabia se a seção estava aberta. O conteúdo recolhido também saiu da ordem de tabulação. A prop `variant` existia na interface e **não fazia nada**; foi removida. No tema escuro (o padrão do `FAQ`), o anel de foco é o inverso, claro: o `--ring` media 2,38:1 ali e sumia. Cada pergunta é um cabeçalho (`nivelDoTitulo`, padrão 3) com o botão dentro: é por ele que quem usa leitor pula de pergunta em pergunta pela tecla H. Acerte o nível conforme a página.

### Anatomia

1. **Item** — Caixa de cantos `rounded-2xl` com borda.
2. **Cabeçalho** — `h2` a `h6` (padrão `h3`), sem estilo próprio.
3. **Botão** — Ocupa a largura: subtítulo opcional (verde no claro, `--ink-inverse-muted` no escuro), título em negrito e a seta num círculo.
4. **Painel** — `role="region"` nomeada pelo botão, com o conteúdo.

### Estados

| Estado | O que muda |
| --- | --- |
| Fechado | `aria-expanded="false"`, painel `hidden` e fora do Tab. |
| Aberto | `aria-expanded="true"`, painel à mostra, seta girada 180° e o painel recebendo foco (`tabIndex={0}`). |
| Foco | Anel por dentro do botão: `ring-ring` no claro, `ring-ring-inverse` no escuro. |
| Hover | Fundo leve no botão; no claro, a sombra do item aumenta. |

### Comportamento

| Situação | O que acontece |
| --- | --- |
| Abrir um item (padrão) | Fecha o que estava aberto — medido: com o Módulo I aberto, abrir o Módulo II fecha o I. |
| Abrir com `allowMultiple` | Os outros continuam abertos — medido: dois abertos. |
| Clicar de novo no aberto | Fecha — e o painel volta ao `hidden`, conferido no teste da ficha. |
| Com `defaultOpenIds` | Abre de saída nos itens pedidos (E65). |
| Modo controlado (`openIds`) | Quem manda é o consumidor; `onOpenChange` recebe a lista nova a cada troca, nos dois modos — conferido no teste da ficha. |

### Relacionados

- [FAQ](https://phorte-design-system.vercel.app/styleguide/md/FAQ.md) — Perguntas frequentes, com o acordeão.
- [CurriculumAccordion](https://phorte-design-system.vercel.app/styleguide/md/CurriculumAccordion.md) — A grade curricular.
- [CourseTabs](https://phorte-design-system.vercel.app/styleguide/md/CourseTabs.md) — Para alternar seções longas.

## Especificação

### Propriedades

| Prop | Tipo | Padrão | Obrigatória | Descrição |
| --- | --- | --- | --- | --- |
| `items` | `{ id: IdDoItem; title: string; subtitle?: string; content: React.ReactNode; }[]` | — | sim |  |
| `allowMultiple` | `boolean` | `false` | não |  |
| `tema` | `TemaDoAcordeao` | `'claro'` | não |  |
| `nivelDoTitulo` | `AccordionItemProps['nivelDoTitulo']` | — | não | Nível do cabeçalho de cada item (padrão 3). Ver `AccordionItem`. |
| `defaultOpenIds` | `IdDoItem[]` | — | não | Itens abertos de início (E65): a grade curricular aberta no módulo atual. Abra no máximo um — vários abertos de saída é uma página comprida sem o índice que o acordeão prometia. |
| `openIds` | `IdDoItem[]` | — | não | Presente = modo controlado (E65): um link direto para uma pergunta. |
| `onOpenChange` | `(ids: IdDoItem[]) => void` | — | não | Dispara a cada abertura e fechamento, nos dois modos, com a lista nova. |

Aceita também: `React.HTMLAttributes<HTMLDivElement>`.

### Medidas

| Parte | Valor | Classe |
| --- | --- | --- |
| Botão (título de uma linha) | 96px de altura em 1280px (medido) | `p-5 md:p-6` |
| Seta | círculo de 32px | `size-8` |

### Tokens de cor

| Token | Valor | Usado como |
| --- | --- | --- |
| `--ink-inverse` | #FAFAFA | `bg-ink-inverse/10`, `bg-ink-inverse/20`, `bg-ink-inverse/5`, `border-ink-inverse/10`, `text-ink-inverse` |
| `--border` | #E5E5E5 | `bg-border`, `border-border` |
| `--muted` | #F4F6F9 | `bg-muted`, `bg-muted/50` |
| `--card` | #FFFFFF | `bg-card` |
| `--foreground` | #1A1A1A | `text-ink` |
| `--ink-inverse-muted` | #C7C7C7 | `text-ink-inverse-muted` |
| `--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` |
| `--ring-inverse` | #FAFAFA | `ring-ring-inverse` |
| `--secondary` | #0B8434 | `text-secondary` |

## Acessibilidade

### Teclado

| Tecla | Faz |
| --- | --- |
| Tab | Vai de botão em botão; com um item aberto, o painel dele entra entre o botão e o próximo — medido. |
| Enter / Espaço | Abre ou fecha o item em foco — medido. |
| ↑ / ↓ | Não andam entre os itens — medido. |

### Leitor de tela

- O botão fica dentro do cabeçalho — o padrão de acordeão da WAI-ARIA —, com `aria-expanded` e `aria-controls` apontando para o painel.
- O painel aberto recebe foco, achado da passada com leitor de tela: sem isso, o conteúdo recém-aberto ficava para trás. É decisão local, e não do padrão ARIA: custa uma parada a mais por item aberto.
- No escuro, o subtítulo é `--ink-inverse-muted`: o verde media 3,18:1 ali — achado pela ficha do tema escuro, na E65.

### O que sustenta o estado

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

## Status e recursos

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