Skip to content

Overlays & navigation

Tabs

Tabs switch between views of the same thing (a client's overview, invoices and payments) without leaving the page. Choose the underline look for page sections, pills for filters inside a card, and segmented for a compact two-to-four way switch. Tabs take icons, counts and a disabled state, and follow the WAI-ARIA tabs pattern with automatic activation.

On this page

Fernhill Studio

Outstanding
€6,840.00
Paid this year
€48,210.00
Average days to pay
18

Usage

components/ui/tabs.tsx
import { Tabs } from "@/components/ui/tabs"; <Tabs  label="Client sections"  items={[    { id: "overview", label: "Overview", content: <Overview /> },    { id: "invoices", label: "Invoices", count: 12, content: <Invoices /> },  ]}/>

Examples

Icons and counts

Counts use tabular figures so the labels don't shift. Disabled tabs are skipped by the arrow keys.

Fernhill Studio

Outstanding
€6,840.00
Paid this year
€48,210.00
Average days to pay
18

Variants

underline (default), pills and segmented. All three share the same keyboard behaviour and markup.

underline

128 invoices across every status.

pills

128 invoices across every status.

segmented

128 invoices across every status.

Full width

fitted stretches the list and shares the width equally, which suits segmented switches in narrow cards and on phones.

€24 per seat, billed every month.

Props

Tabs

  • itemsrequiredTabItem[]default: —The tabs and their panels, in order.
  • variant"underline" | "pills" | "segmented"default: "underline"Visual style.
  • defaultIdstringdefault: —Tab selected on first render (uncontrolled). Defaults to the first enabled tab.
  • valuestringdefault: —Selected tab id (controlled). Pair with onValueChange.
  • onValueChange(id: string) => voiddefault: —Called when the selection changes.
  • fittedbooleandefault: falseStretch the tab list to the full width.
  • labelstringdefault: —Accessible name of the tab list.
  • classNamestringdefault: —Classes for the root element.

TabItem

  • idrequiredstringdefault: —Unique id; also written to data-tab and data-panel.
  • labelrequiredstringdefault: —Tab text.
  • contentrequiredReactNodedefault: —The panel shown when the tab is selected.
  • iconReactNodedefault: —Lucide icon before the label.
  • countnumberdefault: —Small count after the label.
  • disabledbooleandefault: —Not selectable; skipped by the keyboard.

Accessibility

  • Uses role tablist, tab and tabpanel. Each tab has aria-selected and aria-controls; each panel is labelled by its tab.
  • Only the selected tab is in the Tab order. ArrowLeft and ArrowRight move between tabs and select them, Home and End jump to the first and last.
  • Panels are focusable (tabindex=0) so keyboard users can reach content that has no focusable elements.
  • Give the list a name with label when a page has more than one set of tabs.

Suggested