Skip to content
Documentation navigation
Setup

Components

Tabs

A set of layered panels controlled by a tab list.

Basic example

Installation

Choose the package when you want centralized updates, or copy the source through the registry when you want local ownership.

Install the package, import its global tokens once, then use this exact subpath.

# install
pnpm add @constructive-io/ui
# app/globals.css
@import '@constructive-io/ui/globals.css';
# import
import { Tabs } from '@constructive-io/ui/tabs';

When to use

  • Use Tabs to switch among a small set of peer views while keeping one view visible at a time.
  • Use Collapsible for independently expandable supporting sections. Use normal navigation when each destination needs its own URL and browser history entry.

Basic usage

Keep TabsTrigger elements inside TabsList and pair each trigger value with one TabsContent value inside the same Tabs root. When render supplies a non-button trigger, set nativeButton to false.

npm source
tsx
'use client';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@constructive-io/ui/tabs';
function DatabasePanel({ title, children }: {
    title: string;
    children: string;
}) {
    return (<div className="rounded-lg border bg-background p-4 text-sm">
      <p className="text-pretty font-medium">{title}</p>
      <p className="mt-1 text-pretty text-muted-foreground tabular-nums">{children}</p>
    </div>);
}
export function BasicTabsDemo() {
    return (<Tabs defaultValue="overview" className="w-full max-w-[420px]">
        <TabsList className="grid w-full grid-cols-3">
          <TabsTrigger value="overview">Overview</TabsTrigger>
          <TabsTrigger value="usage">Usage</TabsTrigger>
          <TabsTrigger value="settings">Settings</TabsTrigger>
        </TabsList>
        <TabsContent value="overview" className="mt-4">
          <DatabasePanel title="production-db">PostgreSQL 17 · us-east-1 · 12 tables.</DatabasePanel>
        </TabsContent>
        <TabsContent value="usage" className="mt-4">
          <DatabasePanel title="This month">1.2M rows read · 84K rows written.</DatabasePanel>
        </TabsContent>
        <TabsContent value="settings" className="mt-4">
          <DatabasePanel title="Access">Row-level security on · public reads disabled.</DatabasePanel>
        </TabsContent>
      </Tabs>);
}

Controlled and uncontrolled selection

Use defaultValue when Tabs can remember its own selection. Pass value and onValueChange when the selection must synchronize with application state.

Controlled and uncontrolled selection

Examples

Vertical tabsSet orientation to vertical and align the list and panels to match the reading direction.

Accessibility

  • Use a concise label for each TabsTrigger and keep every trigger inside TabsList so Base UI can provide the tablist relationship.
  • Match each trigger value to exactly one TabsContent value. Base UI manages arrow-key navigation, selection, and tab-panel relationships.
  • A disabled tab remains discoverable but unavailable; do not use disabled tabs to hide permissions or required information.

API Reference

Constructive-specific behavior is listed here. Each part links to its inherited platform or primitive contract.

Tabs

Root that manages the active tab and orientation.

PropTypeDefaultDescription
valueanyControlled active tab value.
defaultValueanyInitial active value in uncontrolled usage.
onValueChangeBase UI callbackRuns when the selected tab changes.
orientation'horizontal' | 'vertical''horizontal'Sets layout and arrow-key behavior.

Also accepts Base UI Tabs props.

TabsList

Container that gives its triggers tablist semantics.

Also accepts Base UI Tabs props.

TabsTrigger

Interactive tab that selects the panel with the same value.

PropTypeDefaultDescription
value *anyValue shared with its TabsContent.
disabledbooleanPrevents selection and keyboard activation.
renderReactElement | render functionBase UI composition API.
nativeButtonbooleantrueSet to false when render resolves to a non-button element.

Also accepts Base UI Tabs props.

TabsContent

Panel associated with a TabsTrigger value.

PropTypeDefaultDescription
value *anyValue shared with its TabsTrigger.

Also accepts Base UI Tabs props.