Tabs

Tabs with manual activation, roving focus and an animated indicator.

WAI-ARIA pattern

Installation

npx nuecrea-ui add tabs

Usage

import * as Tabs from '@/components/ui/tabs';

export default function TabsStory() {
  return (
    <main className="grid gap-8">
      <Tabs.Root defaultValue="overview">
        <Tabs.List>
          <Tabs.Tab value="overview">
            Overview
          </Tabs.Tab>
          <Tabs.Tab value="projects">
            Projects
          </Tabs.Tab>
          <Tabs.Tab value="billing" disabled>
            Billing
          </Tabs.Tab>
          <Tabs.Tab value="account">
            Account
          </Tabs.Tab>
          <Tabs.Indicator />
        </Tabs.List>
        <Tabs.Panel value="overview">
          Workspace stats and activity.
        </Tabs.Panel>
        <Tabs.Panel value="projects">
          Milestones and deadlines.
        </Tabs.Panel>
        <Tabs.Panel value="billing" keepMounted>
          Plans and invoices.
        </Tabs.Panel>
        <Tabs.Panel value="account">
          Profile and preferences.
        </Tabs.Panel>
      </Tabs.Root>

      <Tabs.Root defaultValue="general" orientation="vertical">
        <Tabs.List>
          <Tabs.Tab value="general">
            General
          </Tabs.Tab>
          <Tabs.Tab value="security">
            Security
          </Tabs.Tab>
          <Tabs.Indicator />
        </Tabs.List>
        <Tabs.Panel value="general">
          Name, language and time zone.
        </Tabs.Panel>
        <Tabs.Panel value="security">
          Password and two-factor authentication.
        </Tabs.Panel>
      </Tabs.Root>
    </main>
  );
}

API reference

Tabs.Root

Groups the tabs and panels; owns the active value. Renders <div>.

PropTypeDefaultDescription
valueunknown—Controlled active value.
defaultValueunknown—Initial active value. Defaults to the first tab.
orientation'horizontal' | 'vertical'"horizontal"Arrow-key axis and layout.
EventPayloadDescription
onValueChangeunknownFired when a tab is activated. Angular: the `value` model's change event.
Data attributePresent when
data-orientationalways: horizontal | vertical
data-activation-directionalways: left | right | up | down | none, relative to the previous active tab

Tabs.List

The tablist. Arrow keys move focus (looping), Home/End jump. Renders <div> with role tablist.

PropTypeDefaultDescription
activateOnFocusbooleanfalseActivate tabs as arrow keys focus them.
loopFocusbooleantrueWrap focus at the ends.
Data attributePresent when
data-orientationalways: horizontal | vertical
data-activation-directionalways: left | right | up | down | none, relative to the previous active tab

Tabs.Tab

A tab button. Disabled tabs stay focusable but cannot be activated. Renders <button> with role tab.

PropTypeDefaultDescription
valueunknown—Required. Matches a Panel's value.
disabledbooleanfalseCannot be activated (aria-disabled).
Data attributePresent when
data-orientationalways: horizontal | vertical
data-disableddisabled
data-activation-directionalways: left | right | up | down | none, relative to the previous active tab
data-activethe active tab

Tabs.Indicator

Highlights the active tab, positioned by CSS variables. Renders <span> with role presentation.

Data attributePresent when
data-orientationalways: horizontal | vertical
data-activation-directionalways: left | right | up | down | none, relative to the previous active tab
CSS variableDescription
--active-tab-leftActive tab left in px, relative to the list.
--active-tab-rightActive tab right in px, relative to the list.
--active-tab-topActive tab top in px, relative to the list.
--active-tab-bottomActive tab bottom in px, relative to the list.
--active-tab-widthActive tab width in px, relative to the list.
--active-tab-heightActive tab height in px, relative to the list.

Tabs.Panel

Content for one tab. Hidden panels are not rendered (React) or hidden (Angular) unless keepMounted. Renders <div> with role tabpanel.

PropTypeDefaultDescription
valueunknown—Required. Matches a Tab's value.
keepMountedbooleanfalseKeep in the DOM while hidden.
Data attributePresent when
data-orientationalways: horizontal | vertical
data-activation-directionalways: left | right | up | down | none, relative to the previous active tab
data-hiddenhidden (keepMounted) or animating out
data-indexalways: panel index (React counts mounted panels only)
data-starting-styleanimating in
data-ending-styleanimating out

Keyboard

KeyAction
ArrowRight / ArrowDownFocus next tab (by orientation), wrapping.
ArrowLeft / ArrowUpFocus previous tab, wrapping.
Home / EndFocus first / last tab.
Enter / SpaceActivate the focused tab.
TabMove focus into the active panel.