Components / core

Tabs

View Switcher - Amber Underline on Active Tab

01 Preview

02 Usage

View switcher. Amber underline marks the active tab; add index for zero-padded ordinals.

Give each item content and Tabs renders a real ARIA tabs widget — tablist/tab/tabpanel, roving tabindex, arrow-key navigation — and owns the switching itself:

<Tabs
  index
  aria-label="Sections"
  defaultValue="work"
  items={[
    { id: 'work', label: 'Work', content: <WorkList /> },
    { id: 'writing', label: 'Writing', content: <Essays /> },
    { id: 'about', label: 'About', content: <Bio /> },
  ]}
/>

Without content it renders a plain navigation rail and deliberately drops the tab roles — role="tab" pointing at no panel reads worse to a screen reader than no role at all. Use that form only when something else does the switching, and wire the panel yourself:

<Tabs
  aria-label="Sections"
  value={view}
  items={[
    { id: 'work', label: 'Work' },
    { id: 'writing', label: 'Writing' },
  ]}
  onChange={(id) => setView(id)}
/>

Prefer the content form. Always pass aria-label (or aria-labelledby): with panels it names the role="tablist"; without them the rail takes role="group" so the name is exposed rather than sitting inert on a role-less div. Unnamed and panel-less, it stays a plain <div> and claims nothing.

Controlled: value + onChange. Uncontrolled: defaultValue only.

03 Props

PropTypeDefaultNotes
items* TabItem[]
value string Active tab id (controlled).
defaultValue string Initial active tab id (uncontrolled). Defaults to the first item.
onChange (id: string) => void Fires with the selected tab id.
index boolean false Prefix each tab with a zero-padded index.
aria-label string Accessible name for the tab rail.

Also accepts every attribute of Omit<React.HTMLAttributes<HTMLDivElement>, 'onChange'> — they are spread onto the root element. className is merged, not replaced, and ref is forwarded.

04 TabItem

PropTypeDefaultNotes
id* string
label* React.ReactNode
content React.ReactNode Panel body for this tab. Supply it on every item to get a real tab/tabpanel widget.

05 Import

import { Tabs } from '@denizarsan/darsan.design';
import '@denizarsan/darsan.design/styles.css';