Navigation · astro-ui · Tabs
TabsJS
WAI-ARIA tab switcher — line, pill, and card variants.
Tabs implements the WAI-ARIA tabs pattern: SSR renders the list with the initial tab pre-selected, panels hide via the hidden attribute, and a small inline script wires click + arrow-key navigation with automatic activation. Without JS everything stays visible and meaningful.
Features
- WAI-ARIA tabs pattern: roving tabindex, automatic activation
- Arrow keys, Home/End navigation; RTL-aware
- 3 variants: line (underline), pill, card (segmented)
- 5 sizes, horizontal or vertical orientation
- SSR pre-selection; panels visible without JS
- Automatic tab/panel id + aria wiring
Usage
---
import { Tabs } from "astro-ui";
---
<Tabs id="settings" ariaLabel="Settings" defaultValue="billing"
items={[
{ value: "account", label: "Account" },
{ value: "billing", label: "Billing" },
]}>
<div data-tab="account">Account panel.</div>
<div data-tab="billing">Billing panel.</div>
</Tabs>Demos
Line variant
Account panel.
Billing panel.
<Tabs ariaLabel="Settings" defaultValue="billing"
items={[{ value: "account", label: "Account" }, { value: "billing", label: "Billing" }]}>
<div data-tab="account">Account panel.</div>
<div data-tab="billing">Billing panel.</div>
</Tabs>Card variant
Panel one.
Panel two.
<Tabs variant="card" ariaLabel="View"
items={[{ value: "preview", label: "Preview" }, { value: "code", label: "Code" }]}>
<div data-tab="preview">…</div>
<div data-tab="code">…</div>
</Tabs>Vertical
General settings.
Security settings.
<Tabs orientation="vertical" ariaLabel="Settings"
items={[{ value: "general", label: "General" }, { value: "security", label: "Security" }]}>
<div data-tab="general">…</div>
<div data-tab="security">…</div>
</Tabs>API
Props
| Prop | Type | Default | Description |
|---|---|---|---|
items | TabItem[] | [] | Tabs in display order: { value, label, disabled? }. |
defaultValue | string | first enabled | Initially selected tab. |
variant | "line" | "pill" | "card" | "line" | Visual style. |
size | "xs" | "sm" | "md" | "lg" | "xl" | "md" | Scale. |
orientation | "horizontal" | "vertical" | "horizontal" | Layout direction. |
ariaLabel | string | — | Accessible name for the tab list. |
id | string | recommended | Prefixes generated tab/panel ids. |
class | string | — | Merged via cn(); Tailwind classes welcome. |
id | string | — | Element id. |
Slots
| Slot | Description |
|---|---|
default | Panel elements, each carrying data-tab="<value>". |
Accessibility
Implemented accessibility features — semantics, ARIA wiring, and keyboard behavior that ship with the component.
- Full ARIA tabs pattern:
role="tablist"/tab/tabpanel aria-selected,aria-controls, andaria-labelledbywire the relationships- Arrow keys move between tabs with roving
tabindex(script)
FAQ
Does this this work without JS?
The tab list and all panels render server-side; without JS every panel stays visible so content is never lost.
Multiple groups on one page?
Give each a unique id — generated tab/panel ids derive from it.
Changelog
Version history mentioning Tabs.
v0.1.0 — 2026-11-11
added
- Navigation (7): Tabs, Breadcrumb, Pagination, Stepper, Tree, Navbar, Sidebar.
- Native-first interactive behavior: Dialog, AlertDialog, and Sheet on
<dialog>; Accordion and Collapsible on<details>; Tabs, Menu, Tree, and Combobox with WAI-ARIA roles and scoped keyboard scripts.