# Tabs
One strip, several panels.
- Group: Navigation
- Import: `import { Tabs } from '@misoto22/folio'`
- Page: https://ui.misoto22.com/components/tabs/
- Related: accordion
## Anatomy
- **Root** (required) — Tabs — Radix’s root, re-exported. It draws nothing and owns everything: value or defaultValue, and activationMode. With neither value nor defaultValue no tab is selected and no panel is mounted.
- **Tab strip** (required) — TabsList — the role="tablist" row, sitting on one hairline rule and scrolling on its own axis with scroll-slim. It has no accessible name unless you give it one.
- **Tab** (required) — TabsTrigger, at the md control height with its label on one line. Every tab carries the 2px active marker, transparent until it is the selected one; the marker is pulled onto the strip’s own border with -mb-px so the two share a line rather than stacking into a 3px edge.
- **Panel** — TabsContent, paired to its tab by matching value. Mounted only while it is the selected one, and marked data-folio-animated so its entrance is dropped for a reader who asked for less motion.
## Best practices
### Do
- Give the root a defaultValue or a value: with neither, nothing matches, every panel stays unmounted, and the page renders a strip above an empty space with nothing to say what is missing.
- Match each trigger’s value to a panel’s value exactly — the pairing is string equality, and a typo is not an error but a tab that opens onto nothing.
- Pass activationMode="manual" when a panel fetches or renders something expensive: the default is automatic, so ← and → select as they move and arrowing across four tabs starts four loads before the reader has stopped.
- Give TabsList an aria-label on a page with more than one set: Radix names the tablist after nothing, and two unnamed tablists are two “tab list”s a reader cannot tell apart.
### Don’t
- An unselected panel is unmounted, not hidden — find-in-page cannot reach its text, a print takes only the panel that was open, and a half-filled form in another tab has lost what was typed into it by the time the reader comes back.
- The selected tab lives in React state, not in the URL: a reader who reloads or shares the page lands on the first panel, so anything worth linking to needs value lifted into a query parameter.
- Tabs are not a way to fit more in: the strip scrolls silently, and a sixth tab past the fold looks exactly like a page that only has five.
## Accessibility
- The strip scrolls rather than wrapping: a wrapped second row moves every tab below it and the reader loses the one they were about to click.
- 44px tall, because a tab is a pointer target like any other.
## Keyboard
- Tab — Moves into the strip, and out of it — the whole strip is one stop.
- ← / → — Moves between tabs and switches the panel with them.
- Home / End — Jumps to the first or last tab.
## Tabs
Accessible tabs with a moving marker and optional horizontal drag gestures.
## TabsList
The tab strip. Scrolls horizontally rather than wrapping. A wrapped second row of tabs moves every tab below it when the strip grows, and the reader loses the one they were about to click.
## TabsTrigger
One tab. The active marker is a 2px ink rule pulled onto the strip's own border with `-mb-px`, so the two occupy the same line instead of stacking into a 3px edge. 44px tall, because a tab is a pointer target like any other.
## TabsContent
The panel paired to a TabsTrigger by matching `value`.
## Example — default
```tsx
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@misoto22/folio'