Tabs

Composable layout tab container for switching between views.

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

Quick StartLink

Compose tab buttons and panels using subcomponents:

tsx
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 panel...</div>}
        {activeTab === 'tab-2' && <div>Detailed API reference description...</div>}
      </Tabs.Content>
    </Tabs>
  )
}

Composable SubcomponentsLink

The Tabs primitive provides the following namespaces for layout customization:

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

Component PropsLink

ComponentBaseProps (Common)Link

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

Tabs.Item PropsLink

PropertyTypeDefaultDescription
idstringRequiredUnique selector key matching the tab content panel.
selectedbooleanfalseActive highlighted selection state.
disabledbooleanfalsePrevents selection click triggers.
onClick() => voidundefinedActive selection callback handler.
onKeyDown(e: KeyboardEvent) => voidundefinedKey press activation callback handler.

Tabs.Indicator PropsLink

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

Customization & statesLink

Tabs is a self-contained primitive (not React Aria) and fully style-neutral. Tabs.Item is a <button role="tab"> that exposes its selection through data-selected and aria-selected, so the active tab is styled from CSS with Tailwind v4 data-[selected=true]: variants. Tabs.Indicator is the themed moving highlight — position it with style and color it through className.

State / SlotMechanism
data-selectedOn Tabs.Item, "true" / "false" — style with data-[selected=true]:
aria-selectedAccessibility mirror of the selection state on Tabs.Item
Tabs.Item classNamePassthrough; tab visuals (color, borders, padding) from the theme
Tabs.Indicator classNamePassthrough; color and height of the active underline
Tabs.Indicator styleDynamic positioning (transform, width) of the highlight
Tabs.List / Tabs.ContentclassName passthrough, no state

Tailwind v4:

tsx
<Tabs.Item
  id="overview"
  selected={activeTab === 'overview'}
  className="px-4 py-2 text-sm border-b-2 border-transparent text-muted
             data-[selected=true]:text-primary-500 data-[selected=true]:border-primary-500"
>
  Overview
</Tabs.Item>
Last updated on October 18, 2026

Was this page helpful?