# Tabs

Alternância de conteúdo relacionado com lista de abas, gatilhos e painéis.

> Documentação do Sinapse DS. Snippets shadcn usam os componentes do seu projeto (`@/components/ui/*`); snippets HTML usam as classes `itps-*` do CSS Sinapse (`/css/<versão>/`, veja `/comecar.md`). Componentes do site de documentação não fazem parte do DS.

- Categoria: Ações & Navegação
- Status: stable
- Relacionados: /componentes/breadcrumb.md, /componentes/side-panel.md

## Em cada stack

- HTML e Astro: Classes `itps-*` do CSS Sinapse, com todas as variantes desta página.
- React e Vue: Componentes padrão do shadcn (`tabs`) com o tema Sinapse: cores, fonte e raio vêm do tema, e as variantes `itps-*` desta página existem só no HTML.

**React/Next (shadcn/ui)**

```tsx
import {
  Tabs,
  TabsContent,
  TabsList,
  TabsTrigger,
} from '@/components/ui/tabs'

export function TabsExample() {
  return (
    <Tabs defaultValue="overview" className="w-[420px]">
      <TabsList>
        <TabsTrigger value="overview">Visão geral</TabsTrigger>
        <TabsTrigger value="details">Detalhes</TabsTrigger>
        <TabsTrigger value="history">Histórico</TabsTrigger>
      </TabsList>
      <TabsContent value="overview">Conteúdo da visão geral.</TabsContent>
      <TabsContent value="details">Conteúdo de detalhes.</TabsContent>
      <TabsContent value="history">Histórico do paciente.</TabsContent>
    </Tabs>
  )
}
```

**Vue 3/Nuxt 4 (shadcn-vue)**

```vue
<script setup lang="ts">
import {
  Tabs,
  TabsContent,
  TabsList,
  TabsTrigger,
} from '@/components/ui/tabs'
</script>

<template>
  <Tabs default-value="overview" class="w-[420px]">
    <TabsList>
      <TabsTrigger value="overview">Visão geral</TabsTrigger>
      <TabsTrigger value="details">Detalhes</TabsTrigger>
      <TabsTrigger value="history">Histórico</TabsTrigger>
    </TabsList>
    <TabsContent value="overview">Conteúdo da visão geral.</TabsContent>
    <TabsContent value="details">Conteúdo de detalhes.</TabsContent>
    <TabsContent value="history">Histórico do paciente.</TabsContent>
  </Tabs>
</template>
```

**HTML (copy-first)**

```html
<div class="itps-tabs" data-itps-tabs>
  <div class="itps-tabs__list" role="tablist" aria-label="Dados do paciente">
    <button
      type="button"
      class="itps-tabs__trigger"
      id="patient-overview-tab"
      role="tab"
      aria-controls="patient-overview-panel"
      aria-selected="true"
      tabindex="0"
    >
      Visão geral
    </button>
    <button
      type="button"
      class="itps-tabs__trigger"
      id="patient-details-tab"
      role="tab"
      aria-controls="patient-details-panel"
      aria-selected="false"
      tabindex="-1"
    >
      Detalhes
    </button>
    <button
      type="button"
      class="itps-tabs__trigger"
      id="patient-history-tab"
      role="tab"
      aria-controls="patient-history-panel"
      aria-selected="false"
      tabindex="-1"
    >
      Histórico
    </button>
  </div>

  <div class="itps-tabs__panel" id="patient-overview-panel" role="tabpanel" aria-labelledby="patient-overview-tab" tabindex="0">
    Conteúdo da visão geral.
  </div>
  <div class="itps-tabs__panel" id="patient-details-panel" role="tabpanel" aria-labelledby="patient-details-tab" tabindex="0" hidden>
    Conteúdo de detalhes.
  </div>
  <div class="itps-tabs__panel" id="patient-history-panel" role="tabpanel" aria-labelledby="patient-history-tab" tabindex="0" hidden>
    Histórico do paciente.
  </div>
</div>
```

## Instalação

O comando instala o Tabs da sua stack com o tema Sinapse. Configure o registry uma vez por projeto em [Comece por aqui](/comecar).

**terminal · React/Next**

```sh
pnpm dlx shadcn@latest add @sinapse/tabs
```

**terminal · Vue 3/Nuxt 4**

```sh
pnpm dlx shadcn-vue@latest add https://dsystem.sinapse.org.br/r/vue/tabs.json
```

Sem shadcn, não há instalação por componente: use o CSS Sinapse e as classes da API copy-first desta página.

## Uso

Em React/Next com shadcn/ui e Vue 3/Nuxt 4 com shadcn-vue, use os componentes compostos `Tabs`, `TabsList`, `TabsTrigger` e `TabsContent`. Eles carregam estado e navegação por teclado da stack.

Use `itps-tabs` quando precisar do contrato copy-first em HTML ou wrappers finos. Este site usa `src/scripts/tabs.ts` (não incluído no pacote) para inicializar `[data-itps-tabs]`; em produto, mantenha o mesmo contrato ou use o componente da sua stack.

## Exemplos

### Estrutura

| Peça | React/Next e Vue 3/Nuxt 4 | HTML |
|------|--------------------------|------|
| Raiz | `Tabs defaultValue="..."` | `itps-tabs[data-itps-tabs]` |
| Lista | `TabsList` | `itps-tabs__list[role="tablist"]` |
| Trigger | `TabsTrigger value="..."` | `itps-tabs__trigger[role="tab"]` |
| Painel | `TabsContent value="..."` | `itps-tabs__panel[role="tabpanel"]` |

### Com ícones

Use ícones quando eles ajudam a diferenciar seções com rótulos curtos. O ícone deve vir antes do texto e permanecer decorativo.

**HTML (copy-first)**

```html
<div class="itps-tabs" data-itps-tabs>
  <div class="itps-tabs__list" role="tablist" aria-label="Projeto">
    <button
      type="button"
      class="itps-tabs__trigger"
      id="project-summary-tab"
      role="tab"
      aria-controls="project-summary-panel"
      aria-selected="true"
      tabindex="0"
    >
      <i class="ti ti-layout-dashboard" aria-hidden="true"></i>
      <span>Resumo</span>
    </button>
    <button
      type="button"
      class="itps-tabs__trigger"
      id="project-files-tab"
      role="tab"
      aria-controls="project-files-panel"
      aria-selected="false"
      tabindex="-1"
    >
      <i class="ti ti-folder" aria-hidden="true"></i>
      <span>Arquivos</span>
    </button>
    <button
      type="button"
      class="itps-tabs__trigger"
      id="project-team-tab"
      role="tab"
      aria-controls="project-team-panel"
      aria-selected="false"
      tabindex="-1"
    >
      <i class="ti ti-users" aria-hidden="true"></i>
      <span>Equipe</span>
    </button>
  </div>

  <div class="itps-tabs__panel" id="project-summary-panel" role="tabpanel" aria-labelledby="project-summary-tab" tabindex="0">
    Resumo executivo.
  </div>
  <div class="itps-tabs__panel" id="project-files-panel" role="tabpanel" aria-labelledby="project-files-tab" tabindex="0" hidden>
    Lista de arquivos.
  </div>
  <div class="itps-tabs__panel" id="project-team-panel" role="tabpanel" aria-labelledby="project-team-tab" tabindex="0" hidden>
    Membros do time.
  </div>
</div>
```

### Estados e teclado

| Estado | React/Next e Vue 3/Nuxt 4 | HTML |
|--------|--------------------------|------|
| Ativa inicial | `defaultValue` | `aria-selected="true"` + `tabindex="0"` |
| Inativa | valor diferente do ativo | `aria-selected="false"` + `tabindex="-1"` |
| Painel oculto | gerenciado por `TabsContent` | `hidden` no painel inativo |

O teclado esperado é ArrowLeft/ArrowRight para navegar, Home/End para extremos e foco no trigger ativo.

## API copy-first

| Classe/atributo | Uso |
|-----------------|-----|
| `itps-tabs` | Wrapper visual e raiz de comportamento. |
| `data-itps-tabs` | Marca a raiz inicializável pelo script. |
| `itps-tabs__list` | Contêiner com `role="tablist"`. |
| `itps-tabs__trigger` | Botão com `role="tab"`. |
| `itps-tabs__panel` | Painel com `role="tabpanel"`. |
| `aria-selected` | Comunica qual trigger está ativo. |
| `aria-controls` | Liga trigger ao painel. |
| `aria-labelledby` | Liga painel ao trigger. |
| `tabindex` | Mantém foco no trigger ativo e nos painéis focáveis. |
| `hidden` | Oculta painéis inativos. |
| `ArrowLeft` / `ArrowRight` | Navegam entre triggers. |
| `Home` / `End` | Levam para o primeiro ou último trigger. |

## Acessibilidade

Use `role="tablist"` no contêiner de tabs, `role="tab"` nos botões e `role="tabpanel"` nos painéis. Ligue cada tab ao painel com `aria-controls`; ligue cada painel à tab com `aria-labelledby`. Atualize `aria-selected`, `tabindex` e `hidden` quando a tab ativa muda.
