Stable in React
Tabs
A component for toggling between related panels on the same page.
Install#
One package per framework. Tabs's parts come from it; the anatomy tab at the top shows how they nest.
bun add @▢▢▢▢/reactFive parts. The example uses five of them; the data does not say which are required.
Tabs.RootGroups the tabs and the corresponding panels.Tabs.ListGroups the individual tab buttons.Tabs.TabAn individual interactive tab button that toggles the corresponding panel.Tabs.IndicatorA visual indicator that can be styled to match the position of the currently active tab.Tabs.PanelA panel displayed when the corresponding tab is active.
Examples#
Common ways to put it to work. Each one runs live.
Panels slide in from the side given by data-activation-direction.
TabsAnimatedPanels.tsxStyling and accessibility#
The parts ship no styles. Style their states with these attributes; the CSS tab at the top has a sheet. The same CSS works in all five frameworks.
[data-activation-direction]Indicates the direction of the activation (based on the previous active tab). On Root, List, Tab, Indicator, Panel.[data-orientation]Indicates the orientation of the tabs. On Root, List, Tab, Indicator, Panel.[data-disabled]Present when the tab is disabled. On Tab.[data-active]Present when the tab is active. On Tab.--active-tab-leftIndicates the distance on the left side from the parent's container if the tab is active. On Indicator.--active-tab-rightIndicates the distance on the right side from the parent's container if the tab is active. On Indicator.--active-tab-topIndicates the distance on the top side from the parent's container if the tab is active. On Indicator.--active-tab-bottomIndicates the distance on the bottom side from the parent's container if the tab is active. On Indicator.--active-tab-widthIndicates the width of the tab if it is active. On Indicator.--active-tab-heightIndicates the height of the tab if it is active. On Indicator.[data-index]Indicates the index of the tab panel. On Panel.[data-hidden]Present when the panel is hidden. On Panel.[data-starting-style]Present when the panel begins animating in. On Panel.[data-ending-style]Present when the panel is animating out. On Panel.
Keyboard
- ArrowRightArrowLeftMoves focus to the next or previous tab without activating it (
ArrowDownandArrowUpwhen vertical) On List. - ArrowRightArrowLeftWith
activateOnFocus, moves focus and activates the tab On List. - ArrowRightFrom the last tab, wraps to the first while
loopFocusis on On List. - HomeMoves focus to the first tab On List.
- EndMoves focus to the last tab On List.
- EnterSpaceActivates the focused tab On Tab.
Set for you
a screen reader announces a set of tabs and which arrow keys move in itListrole="tablist",aria-orientation="vertical"when verticaleach tab is read with its state and tied to its panelTabrole="tab",aria-selected,aria-controlsto its panelthe panel is read with the tab's namePanelrole="tabpanel",aria-labelledbyto its tabkeyboard users can reach a panel that has no focusable contentPaneltabindex="0"while activethe moving highlight is not readIndicatorrole="presentation"
API reference#
12 props across 5 parts, in React syntax, and className, style, render once for every part. Open a row to try it.
Tabs · all partsclassNameCSS class applied to the element, or a function that
returns a class based on the component's state.string | ((state: State) => string | undefined)styleStyle applied to the element, or a function that
returns a style object based on the component's state.React.CSSProperties | ((state: State) => React.CSSProperties | undefined)renderAllows you to replace the component's HTML element
with a different tag, or compose it with another component.React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, State>Use it in React#
What differs from the React API. Switch the framework at the top of the page.
@▢▢▢▢/react is the React 19 package. Its parts, props, data attributes and error messages are upstream Base UI's, and upstream's own tests run against it.
- Parts
Each component is its own entry point and exports one namespace named after it.
import { Switch } from '@base-ui-next/react/switch' export function Example() { return ( <Switch.Root> <Switch.Thumb /> </Switch.Root> ) }A part renders the element its API reference names, such as a
<span>forSwitch.Root. - Props and events
Props and callbacks have upstream's names and signatures:
onCheckedChange(checked, details),onOpenChange(open, details),onValueChange(value, details).detailscarriesreason,event,cancel()andallowPropagation(). Native handlers are React's (onClick,onKeyDown), andevent.preventBaseUIHandler()stops a part's own handler. - Styling
classNametakes a string or a function(state) => string;styletakes an object or a function(state) => object. The state'sdata-*attributes are on the element for CSS. renderrendertakes an element (render={<a href="/docs" />}) or a function(props, state) => elementthat spreadspropson what it returns.- Refs
refreaches the part's element. Imperative handles are ref props, as upstream:inputRef, andactionsRef({ validate }on Field and Form,{ unmount, close }on Dialog). - Binding
A part is controlled when its value prop (
checked,open,value) is set, and uncontrolled with thedefaultform (defaultChecked,defaultOpen,defaultValue). React has no two-way binding: pair the value with its change callback. - From @base-ui/reactChange the import from
@base-ui/react/<component>to@▢▢▢▢/react/<component>. - From @base-ui/reactNothing else changes: props, parts, data attributes and errors are the same.