Tabbed navigation between related views with an animated active indicator.
import { Tabs } from '@oztix/roadie-components/tabs'
emphasis controls the visual treatment of the list and the indicator. The active indicator animates between tabs in every variant. Only the appearance of the indicator changes.
A high-contrast segmented control with a solid inverted pill behind the active tab. Use when tabs need to stand out against a busy or photographic background.
A segmented control with a raised pill that slides between active tabs. Use inside cards and toolbars.
A ghost segmented control. It has no track, just a tinted pill that slides behind the active tab. Use when the surrounding surface already provides framing.
A flat row with a sliding underline. Use for in-page section navigation where tabs should defer to the surrounding content. Under forced colours the underline takes the system highlight colour.
A tab that holds only an icon becomes a circle at every size and emphasis, and the indicator follows its shape. With subtler, the underline runs the width of the circle. Give each one an aria-label, because the icon has no text for assistive tech to read. Roadie warns in development when a name is missing.
intent cascades down to descendants via CSS custom properties. The active indicator picks up the intent's strong colour in subtler emphasis.
Disabled tabs are skipped during keyboard navigation and ignore clicks.
Use the Base UI render prop to access the active state and switch a Phosphor icon's weight between bold and fill.
Pass direction='vertical' to render a column of left-aligned tabs. With emphasis='subtler' the active indicator becomes a 2px bar on the left edge that slides between tabs; the pill emphases (strong, normal, subtle) keep their full-rect shape around the active tab in vertical mode.
A horizontal list never wraps. When the tabs don't fit, the list scrolls sideways, and it scrolls the active tab into view.
By default, panels mount only when active. Pass keepMounted on Tabs.Panel to preserve in-flight state (forms, scroll position, video playback) when switching tabs.
Breadcrumb or a sidebar instead when tabs would otherwise represent separate pages.emphasis='normal' inside cards or toolbars. The segmented track gives the control its own visual frame. Reach for emphasis='strong' when tabs need to stand out against a busy or photographic background, emphasis='subtle' for a quieter ghost-segmented look, and emphasis='subtler' for a flat underline-only row that defers to the surrounding content.Tabs.Indicator inside Tabs.List as a sibling of the tabs themselves, not inside a tab. The indicator is positioned absolutely against the list and reads its geometry from Base UI's --active-tab-* CSS variables.Use Tabs when each choice shows its own content below. When the choice changes how the same content is filtered or shown, such as a date range or a list or grid view, use a toggle group.
<Tabs.Tab value='overview'>Overview</Tabs.Tab><Tabs.Tab value='settings'>Settings</Tabs.Tab>
Do
Each tab opens its own panel with different content.
<Tabs.Tab value='7d'>7 days</Tabs.Tab><Tabs.Tab value='30d'>30 days</Tabs.Tab>
Don’t
Tabs that only change the range of one chart. There are no separate panels, so use a ToggleGroup.
Arrow keys move focus between tabs (ArrowLeft/ArrowRight for horizontal, ArrowUp/ArrowDown for vertical). Home and End jump to the first and last tab. Enter and Space activate the focused tab.activateOnFocus on Tabs.List to switch panels as focus moves, instead of waiting for Enter/Space.role='tablist', role='tab', role='tabpanel', aria-controls, aria-selected, and aria-orientation automatically.prefers-reduced-motion: reduce. The indicator still updates position, just without the transition.CSS class applied to the element, or a function that returns a class based on the component's state.
The default value. Use when the component is not controlled. When the value is `null`, no Tab will be active.
Defaults to 0.
The value of the currently active `Tab`. Use when the component is controlled. When the value is `null`, no Tab will be active.
Callback invoked when new value is being set. The event `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.
Sets the intent cascade for descendant tabs.
Visual treatment for the list and indicator. See the emphasis ladder comment in `variants.ts` for the full description of each option.
Defaults to 'normal'.
Tab height and typography size.
Defaults to 'md'.
Layout flow direction. `vertical` stacks the tabs in a column. The active indicator follows the axis: in `subtler` emphasis the underline becomes a left-edge bar, while the pill emphases (`strong` / `normal` / `subtle`) keep their full-rect shape around the active tab.
Defaults to 'horizontal'.
CSS class applied to the element, or a function that returns a class based on the component's state.
Inherited from TabsIndicatorProps
Whether to render itself before React hydrates. This minimizes the time that the indicator isn't visible after server-side rendering.
Defaults to true.
CSS class applied to the element, or a function that returns a class based on the component's state.
Inherited from TabsListProps
Whether to automatically change the active tab on arrow key focus. Otherwise, tabs will be activated using <kbd>Enter</kbd> or <kbd>Space</kbd> key press.
Defaults to false.
Whether to loop keyboard focus back to the first item when the end of the list is reached while using the arrow keys.
Defaults to true.
CSS class applied to the element, or a function that returns a class based on the component's state.
Inherited from TabsPanelProps
The value of the TabPanel. It will be shown when the Tab with the corresponding value is active.
Whether to keep the HTML element in the DOM while the panel is hidden.
Defaults to false.
CSS class applied to the element, or a function that returns a class based on the component's state.
Render the tab as a routed anchor instead of a `<button>`. Useful for tabbed navigation where each tab maps to a route. Internal hrefs route through `RoadieLinkProvider`. Note: pressing Enter on a focused link-tab triggers native browser navigation immediately. For controlled `Tabs.value`, derive the value from the route (e.g. `usePathname()`) rather than from controlled local state — otherwise the active-tab indicator can flicker between selection and route change.
Force external-link treatment when `href` is set.
Override the auto `target='_blank'` default on external hrefs.
Inherited from TabsTabProps
The value of the Tab.
Whether the Tab is disabled. If a first Tab on a `<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.
Inherited from NativeButtonProps
Whether the component renders a native `<button>` element when replacing it via the `render` prop. Set to `false` if the rendered element is not a button (for example, `<div>`).
Defaults to true.