1. Home
  2. ChevronRightUi
  3. ChevronRightTabs

Tabs

Composable layout tabs container for toggling between views.

The Tabs primitive provides a modular, keyboard-navigable component structure for organizing content into discrete pane directories.

It's built on react-aria-components Tabs, so you keep roving tabindex, arrow-key navigation, focus management, and the right aria roles for free. Boltdocs wires Tailwind classes that match the design system — you bring the structure.

Reach for Tabs when you want a small set of mutually exclusive views. For 2–6 short pieces of related content, Tabs is usually right; for navigation between full pages, use Sidebar + OnThisPage instead.


ImportLink

import { Tabs } from 'boltdocs/primitives'

Quick StartLink

Compose tab buttons and panels using sub-components:

import React, { useState } from 'react'
import { Tabs } from 'boltdocs/primitives'

export default function CustomTabs() {
  const [activeTab, setActiveTab] = useState('tab-1')

  return (
    <Tabs>
      <Tabs.List className="border-b border-subtle mb-4">
        <Tabs.Item
          id="tab-1"
          selected={activeTab === 'tab-1'}
          onClick={() => setActiveTab('tab-1')}
          className="px-4 py-2 text-sm font-semibold data-[selected=true]:text-primary-500 border-b-2 border-transparent data-[selected=true]:border-primary-500"
        >
          Overview
        </Tabs.Item>
        <Tabs.Item
          id="tab-2"
          selected={activeTab === 'tab-2'}
          onClick={() => setActiveTab('tab-2')}
          className="px-4 py-2 text-sm font-semibold data-[selected=true]:text-primary-500 border-b-2 border-transparent data-[selected=true]:border-primary-500"
        >
          API Reference
        </Tabs.Item>
      </Tabs.List>

      <Tabs.Content>
        {activeTab === 'tab-1' && <div>Overview content dashboard...</div>}
        {activeTab === 'tab-2' && <div>Detailed API reference description...</div>}
      </Tabs.Content>
    </Tabs>
  )
}

Composable Sub-ComponentsLink

The Tabs primitive provides the following namespaces for layout customisation:

ComponentHTML TagDescriptionProps
Tabs.Root / Tabs<div>Top-level tabs block wrapper.ComponentBaseProps
Tabs.List<div> (tablist)Holds tab category triggers.ComponentBaseProps
Tabs.Item<button> (tab)The individual tab button selector cell.Tabs.Item Props
Tabs.Content<div> (tabpanel)View container wrapping active content sections.ComponentBaseProps
Tabs.Indicator<div>An absolute positioning highlight line showing the active tab.Tabs.Indicator Props

Component PropsLink

ComponentBaseProps (Common)Link

PropertyTypeDefaultDescription
childrenReactNodeundefinedChildren content elements.
classNamestringundefinedCustom CSS utility classes.
styleCSSPropertiesundefinedInline style settings.

Tabs.Item PropsLink

PropertyTypeDefaultDescription
idstringRequiredUnique selector key matching the tab content panel.
selectedbooleanfalseHighlight active selection state.
disabledbooleanfalsePrevents selection click triggers.
onClick() => voidundefinedTriggered selection callback handler.
onKeyDown(e: KeyboardEvent) => voidundefinedKeypress trigger callback handler.

Tabs.Indicator PropsLink

PropertyTypeDefaultDescription
styleCSSPropertiesundefinedDynamic coordinates mapping styles (e.g. transform, width).

PitfallsLink

  • Tabs.Item is selected, not isSelected. React Aria's lower-level API uses isSelected; this primitive aliases it to selected for the common controlled-state flow.
  • Keyboard navigation is automatic. You don't need to wire arrow-key handlers. If you have to, you're probably fighting the primitive — switch to Tabs from react-aria-components directly.
  • Each Tabs.Item needs an id. The id matches a <Tabs.Panel id="..."> for the accessible label association; the example above uses activeTab state to drive the panel manually because the layout decoupled panels from tabs.
Last updated on July 27, 2026

Was this page helpful?