Tabs
A component for toggling between related panels on the same page.
Workspace stats and activity.
import { Tabs } from 'base-ui-solid/tabs';
import styles from './index.module.css';
export default function ExampleTabs() {
return (
<Tabs.Root class={styles.Root} defaultValue="overview">
<Tabs.List class={styles.List}>
<Tabs.Tab class={styles.Tab} value="overview">
Overview
</Tabs.Tab>
<Tabs.Tab class={styles.Tab} value="projects">
Projects
</Tabs.Tab>
<Tabs.Tab class={styles.Tab} value="account">
Account
</Tabs.Tab>
<Tabs.Indicator class={styles.Indicator} />
</Tabs.List>
<div class={styles.PanelViewport}>
<Tabs.Panel class={styles.Panel} value="overview">
<p class={styles.Paragraph}>Workspace stats and activity.</p>
</Tabs.Panel>
<Tabs.Panel class={styles.Panel} value="projects">
<p class={styles.Paragraph}>Milestones and deadlines.</p>
</Tabs.Panel>
<Tabs.Panel class={styles.Panel} value="account">
<p class={styles.Paragraph}>Profile and preferences.</p>
</Tabs.Panel>
</div>
</Tabs.Root>
);
}
Anatomy
Import the component and assemble its parts:
import { Tabs } from 'base-ui-solid/tabs';
<Tabs.Root>
<Tabs.List>
<Tabs.Tab />
<Tabs.Indicator />
</Tabs.List>
<Tabs.Panel />
</Tabs.Root>;
Examples
Animated panels
Animate panels as they activate using the data-starting-style and data-ending-style attributes.
The data-activation-direction attribute indicates which direction the newly active tab is relative to the previously active one, letting panels slide in from the correct side.
Workspace stats and activity.
import { Tabs } from 'base-ui-solid/tabs';
import styles from './index.module.css';
export default function ExampleAnimatedTabs() {
return (
<Tabs.Root class={styles.Root} defaultValue="overview">
<Tabs.List class={styles.List}>
<Tabs.Tab class={styles.Tab} value="overview">
Overview
</Tabs.Tab>
<Tabs.Tab class={styles.Tab} value="projects">
Projects
</Tabs.Tab>
<Tabs.Tab class={styles.Tab} value="account">
Account
</Tabs.Tab>
<Tabs.Indicator class={styles.Indicator} />
</Tabs.List>
<div class={styles.PanelViewport}>
<Tabs.Panel class={styles.Panel} value="overview">
<p class={styles.Paragraph}>Workspace stats and activity.</p>
</Tabs.Panel>
<Tabs.Panel class={styles.Panel} value="projects">
<p class={styles.Paragraph}>Milestones and deadlines.</p>
</Tabs.Panel>
<Tabs.Panel class={styles.Panel} value="account">
<p class={styles.Paragraph}>Profile and preferences.</p>
</Tabs.Panel>
</div>
</Tabs.Root>
);
}
Links
Use the render prop and set nativeButton={false} on <Tabs.Tab> to render tabs as anchor elements.
import { Tabs } from 'base-ui-solid/tabs';
import Link from 'next/link';
<Tabs.Root>
<Tabs.List>
<Tabs.Tab
nativeButton={false}
render={(renderProps) => <Link {...renderProps} href="/overview" />}
value="overview"
>
Overview
</Tabs.Tab>
</Tabs.List>
{/* ... */}
</Tabs.Root>;
API reference
Root
Groups the tabs and the corresponding panels.
Renders a <div> element.
defaultValueTabs.Tab.Value0
null, no Tab will be active.Tabs.Tab.ValuevalueTabs.Tab.Value—
Tab. Use when the component is controlled.
When the value is null, no Tab will be active.Tabs.Tab.ValueonValueChangefunction—
reason is 'none' for user-initiated changes, such as a click
or keyboard navigation; 'initial' for the first automatic selection or
fallback in uncontrolled roots when defaultValue is omitted or
undefined, including when the implicit initial value is disabled or
missing; 'disabled' for automatic fallback when the selected tab becomes
disabled in uncontrolled roots; or 'missing' for automatic fallback when
the selected tab is removed, or when an explicit defaultValue never
matches a mounted tab in uncontrolled roots. For automatic changes, the selected value can be null when no enabled Tab
is available as a fallback. Automatic changes cannot be canceled; calling eventDetails.cancel() for
'initial', 'disabled', or 'missing' has no effect.((value: Tabs.Tab.Value, eventDetails: Tabs.Root.ChangeEventDetails) => void)orientationTabs.Root.Orientation'horizontal'
Tabs.Root.Orientationclassfunction—
JSX.ClassValue | ((state) => JSX.ClassValue)stylefunction—
JSX.CSSProperties | string | ((state) => JSX.CSSProperties | string | undefined)renderfunction—
keyof JSX.IntrinsicElements | Component | ((props, state) => JSX.Element)Data attributes
data-orientationUnion—
'horizontal' | 'vertical'data-activation-directionUnion—
'left' | 'right' | 'up' | 'down' | 'none'Attribute | Description | |
|---|---|---|
data-orientation | Indicates the orientation of the tabs. | |
data-activation-direction | Indicates the direction of the activation (based on the previous active tab). | |
Root.State
type TabsRootState = {
/** The component orientation. */
orientation: Tabs.Root.Orientation;
/** The direction used for tab activation. */
tabActivationDirection: Tabs.Tab.ActivationDirection;
};Root.ChangeEventReason
type TabsRootChangeEventReason = 'none' | 'disabled' | 'missing' | 'initial';Root.ChangeEventDetails
type TabsRootChangeEventDetails = (
{ reason: 'none' } | { reason: 'disabled' } | { reason: 'missing' } | { reason: 'initial' }
) & {
/** The native event associated with the custom event. */
event: Event;
/** Cancels Base UI from handling the event. */
cancel: () => void;
/** Allows the event to propagate in cases where Base UI will stop the propagation. */
allowPropagation: () => void;
/** Indicates whether the event has been canceled. */
isCanceled: boolean;
/** Indicates whether the event is allowed to propagate. */
isPropagationAllowed: boolean;
/** The element that triggered the event, if applicable. */
trigger: Element | undefined;
activationDirection: Tabs.Tab.ActivationDirection;
};Root.Orientation
type TabsRootOrientation = 'horizontal' | 'vertical';List
Groups the individual tab buttons.
Renders a <div> element.
activateOnFocusbooleanfalse
booleanloopFocusbooleantrue
booleanclassfunction—
JSX.ClassValue | ((state) => JSX.ClassValue)stylefunction—
JSX.CSSProperties | string | ((state) => JSX.CSSProperties | string | undefined)renderfunction—
keyof JSX.IntrinsicElements | Component | ((props, state) => JSX.Element)Data attributes
data-orientationUnion—
'horizontal' | 'vertical'data-activation-directionUnion—
'left' | 'right' | 'up' | 'down' | 'none'Attribute | Description | |
|---|---|---|
data-orientation | Indicates the orientation of the tabs. | |
data-activation-direction | Indicates the direction of the activation (based on the previous active tab). | |
List.State
type TabsListState = {
/** The component orientation. */
orientation: Tabs.Root.Orientation;
/** The direction used for tab activation. */
tabActivationDirection: Tabs.Tab.ActivationDirection;
};Tab
An individual interactive tab button that toggles the corresponding panel.
Renders a <button> element.
value*Tabs.Tab.Value—
Tabs.Tab.ValuenativeButtonbooleantrue
<button> element when replacing it
via the render prop.
Set to false if the rendered element is not a button (for example, <div>).booleandisabledboolean—
<Tabs.List> is disabled, it won’t initially be selected.
Instead, the next enabled Tab will be selected.
However, it does not work like this during server-side rendering, as it is not known
during pre-rendering which Tabs are disabled.
To work around it, ensure that defaultValue or value on <Tabs.Root> is set to an enabled Tab’s value.booleanclassfunction—
JSX.ClassValue | ((state) => JSX.ClassValue)stylefunction—
JSX.CSSProperties | string | ((state) => JSX.CSSProperties | string | undefined)renderfunction—
keyof JSX.IntrinsicElements | Component | ((props, state) => JSX.Element)Data attributes
data-orientationUnion—
'horizontal' | 'vertical'data-disabled-—
-data-activation-directionUnion—
'left' | 'right' | 'up' | 'down' | 'none'data-active-—
-Attribute | Description | |
|---|---|---|
data-orientation | Indicates the orientation of the tabs. | |
data-disabled | Present when the tab is disabled. | |
data-activation-direction | Indicates the direction of the activation (based on the previous active tab). | |
data-active | Present when the tab is active. | |
Tab.State
type TabsTabState = {
/** Whether the component should ignore user interaction. */
disabled: boolean;
/** Whether the component is active. */
active: boolean;
/** The component orientation. */
orientation: Tabs.Root.Orientation;
/** The direction used for tab activation. */
tabActivationDirection: Tabs.Tab.ActivationDirection;
};Tab.Value
type TabsTabValue = Tabs.Tab.Value;Tab.ActivationDirection
type TabsTabActivationDirection = 'left' | 'right' | 'up' | 'down' | 'none';Tab.Metadata
type TabsTabMetadata = {
disabled: boolean;
id: string | undefined;
value: Tabs.Tab.Value | undefined;
};Tab.Position
type TabsTabPosition = { left: number; right: number; top: number; bottom: number };Tab.Size
type TabsTabSize = { width: number; height: number };Indicator
A visual indicator that can be styled to match the position of the currently active tab.
Renders a <span> element.
renderBeforeHydrationbooleanfalse
booleanclassfunction—
JSX.ClassValue | ((state) => JSX.ClassValue)stylefunction—
JSX.CSSProperties | string | ((state) => JSX.CSSProperties | string | undefined)renderfunction—
keyof JSX.IntrinsicElements | Component | ((props, state) => JSX.Element)Data attributes
data-orientationUnion—
'horizontal' | 'vertical'data-activation-directionUnion—
'left' | 'right' | 'up' | 'down' | 'none'Attribute | Description | |
|---|---|---|
data-orientation | Indicates the orientation of the tabs. | |
data-activation-direction | Indicates the direction of the activation (based on the previous active tab). | |
CSS variables
--active-tab-bottomnumber—
number--active-tab-heightnumber—
number--active-tab-leftnumber—
number--active-tab-rightnumber—
number--active-tab-topnumber—
number--active-tab-widthnumber—
numberCSS Variable | Description | |
|---|---|---|
--active-tab-bottom | Indicates the distance on the bottom side from the parent’s container if the tab is active. | |
--active-tab-height | Indicates the height of the tab if it is active. | |
--active-tab-left | Indicates the distance on the left side from the parent’s container if the tab is active. | |
--active-tab-right | Indicates the distance on the right side from the parent’s container if the tab is active. | |
--active-tab-top | Indicates the distance on the top side from the parent’s container if the tab is active. | |
--active-tab-width | Indicates the width of the tab if it is active. | |
Indicator.State
type TabsIndicatorState = {
/** The active tab position. */
activeTabPosition: Tabs.Tab.Position | null;
/** The active tab size. */
activeTabSize: Tabs.Tab.Size | null;
/** The component orientation. */
orientation: Tabs.Root.Orientation;
/** The direction used for tab activation. */
tabActivationDirection: Tabs.Tab.ActivationDirection;
};Panel
A panel displayed when the corresponding tab is active.
Renders a <div> element.
value*Tabs.Tab.Value—
Tabs.Tab.Valueclassfunction—
JSX.ClassValue | ((state) => JSX.ClassValue)stylefunction—
JSX.CSSProperties | string | ((state) => JSX.CSSProperties | string | undefined)keepMountedbooleanfalse
booleanrenderfunction—
keyof JSX.IntrinsicElements | Component | ((props, state) => JSX.Element)Data attributes
data-orientationUnion—
'horizontal' | 'vertical'data-activation-directionUnion—
'left' | 'right' | 'up' | 'down' | 'none'data-hidden-—
-data-index-—
-data-starting-style-—
-data-ending-style-—
-Attribute | Description | |
|---|---|---|
data-orientation | Indicates the orientation of the tabs. | |
data-activation-direction | Indicates the direction of the activation (based on the previous active tab). | |
data-hidden | Present when the panel is hidden. | |
data-index | Indicates the index of the tab panel. | |
data-starting-style | Present when the panel begins animating in. | |
data-ending-style | Present when the panel is animating out. | |
Panel.State
type TabsPanelState = {
/** Whether the component is hidden. */
hidden: boolean;
/** The transition status of the component. */
transitionStatus: TransitionStatus;
/** The component orientation. */
orientation: Tabs.Root.Orientation;
/** The direction used for tab activation. */
tabActivationDirection: Tabs.Tab.ActivationDirection;
};Panel.Metadata
type TabsPanelMetadata = { id?: string; value: Tabs.Tab.Value };