Tab components

FREE

Free and open-source React tab components built for modern applications and websites. These tabs are built using React Aria and styled with Tailwind CSS.

Installation

You can add this tabs component using our CLI or manually:

npx untitledui@latest add tabs

Tabs examples

Below are examples and variations of this tabs component:

API reference

Import the parts and assemble them:

import { Tabs } from "@/components/application/tabs/tabs";
 
<Tabs>
    <Tabs.List>
        <Tabs.Item />
    </Tabs.List>
    <Tabs.Panel />
</Tabs>

Tabs

Renders React Aria’s Tabs — all of its props are supported.

Tabs props
PropTypeDefaultDescription
defaultSelectedKeyKey—The initial selected keys in the collection (uncontrolled).
disabledKeysIterable<Key>—The item keys that are disabled. These items cannot be selected, focused, or otherwise interacted with.
idstring—The element's unique identifier.
isDisabledboolean—Whether the TabList is disabled. Shows that a selection exists, but is not available in that circumstance.
keyboardActivation
"automatic""manual"
"manual"Whether tabs are activated automatically on focus or manually.
onSelectionChange((key: Key) => void)—Handler that is called when the selection changes.
orientation
"horizontal""vertical"
"horizontal"The orientation of the tabs.
selectedKeyKey—The currently selected key in the collection (controlled).
Styling (5)
Tabs styling props
PropTypeDefaultDescription
styleStyleOrFunction<TabsRenderProps>—The inline style for the element. A function may be provided to compute the style based on component state.
childrenChildrenOrFunction<TabsRenderProps>—The children of the component. A function may be provided to alter the children based on component state.
slotstring | null—A slot name for the component. Slots allow the component to receive props from a parent component. An explicit null value indicates that the local props completely override all props received from a parent.
classNameClassNameOrFunction<TabsRenderProps>—The CSS className for the element. A function may be provided to compute the class based on component state.
renderDOMRenderFunction<"div", TabsRenderProps>—Overrides the default DOM element with a custom render function. This allows rendering existing components with built-in styles and behaviors such as router links, animation libraries, and pre-styled components.Requirements:
  • You must render the expected element type (e.g. if <button> is expected, you cannot render an <a>).
  • Only a single root DOM element can be rendered (no fragments).
  • You must pass through props and ref to the underlying DOM element, merging with your own prop as appropriate.
Accessibility (4)
Tabs accessibility props
PropTypeDefaultDescription
aria-describedbystring—Identifies the element (or elements) that describes the object.
aria-detailsstring—Identifies the element (or elements) that provide a detailed, extended description for the object.
aria-labelstring—Defines a string value that labels the current element.
aria-labelledbystring—Identifies the element (or elements) that labels the current element.

Also accepts the global HTML attributes (dir, lang, hidden, inert, translate), all standard React DOM event handlers.

Tabs.Item

Renders React Aria’s Tab — all of its props are supported.

Tabs.Item props
PropTypeDefaultDescription
labelReactNode—The label of the tab.
childrenReactNode | ((props: AriaTabRenderProps) => ReactNode)—The children of the tab.
iconReactNode | FC<{ className?: string; }>—Icon component or element to show before the text.
badgestring | number—The badge displayed next to the label.
Props from React Aria (29)
Tabs.Item inherited props
PropTypeDefaultDescription
onClick((e: MouseEvent<FocusableElement>) => void)—Not recommended – use onPress instead. onClick is an alias for onPress provided for compatibility with other libraries. onPress provides additional event details for non-mouse interactions.
onPress((e: PressEvent) => void)—Handler that is called when the press is released over the target.
onPressChange((isPressed: boolean) => void)—Handler that is called when the press state changes.
onPressEnd((e: PressEvent) => void)—Handler that is called when a press interaction ends, either over the target or when the pointer leaves the target.
onPressStart((e: PressEvent) => void)—Handler that is called when a press interaction starts.
onPressUp((e: PressEvent) => void)—Handler that is called when a press is released over the target, regardless of whether it started on the target or not.
onHoverChange((isHovering: boolean) => void)—Handler that is called when the hover state changes.
onHoverEnd((e: HoverEvent) => void)—Handler that is called when a hover interaction ends.
onHoverStart((e: HoverEvent) => void)—Handler that is called when a hover interaction starts.
onBlur((e: FocusEvent<Element, Element>) => void)—Handler that is called when the element loses focus.
onFocus((e: FocusEvent<Element, Element>) => void)—Handler that is called when the element receives focus.
onFocusChange((isFocused: boolean) => void)—Handler that is called when the element's focus status changes.
downloadstring | boolean—Causes the browser to download the linked URL. A string may be provided to suggest a file name.
hrefstring—A URL to link to.
hrefLangstring—Hints at the human language of the linked URL.
pingstring—A space-separated list of URLs to ping when the link is followed.
referrerPolicy
"""no-referrer""no-referrer-when-downgrade""origin""origin-when-cross-origin""same-origin""strict-origin""strict-origin-when-cross-origin""unsafe-url"
—How much of the referrer to send when following the link.
relstring—The relationship between the linked resource and the current page.
routerOptionsRouterOptions—Options for the configured client side router.
targetHTMLAttributeAnchorTarget—The target window for the link.
idKey—The unique id of the tab.
isDisabledboolean—Whether the tab is disabled.
styleStyleOrFunction<AriaTabRenderProps>—The inline style for the element. A function may be provided to compute the style based on component state.
classNameClassNameOrFunction<AriaTabRenderProps>—The CSS className for the element. A function may be provided to compute the class based on component state.
render(props: DetailedHTMLProps<LinkWithRequiredHref, HTMLAnchorElement> | JSX.IntrinsicElements[Fallback], renderProps: T) => ReactElement—Overrides the default DOM element with a custom render function. This allows rendering existing components with built-in styles and behaviors such as router links, animation libraries, and pre-styled components.Note: You can check if 'href' in props in order to tell whether to render an <a> element.Requirements:
  • You must render the expected element type (e.g. if <a> is expected, you cannot render a <button>).
  • Only a single root DOM element can be rendered (no fragments).
  • You must pass through props and ref to the underlying DOM element, merging with your own prop as appropriate.
aria-describedbystring—Identifies the element (or elements) that describes the object.
aria-detailsstring—Identifies the element (or elements) that provide a detailed, extended description for the object.
aria-labelstring—Defines a string value that labels the current element.
aria-labelledbystring—Identifies the element (or elements) that labels the current element.

Also accepts the global HTML attributes (dir, lang, hidden, inert, translate), all standard React DOM event handlers.

Tabs.List

Renders React Aria’s TabList — all of its props are supported.

Tabs.List props
PropTypeDefaultDescription
size
"sm""md"
"sm"The size of the tab list.
type
"line""button-brand""button-gray""button-border""button-minimal""underline"
"button-brand"The type of the tab list.
orientation
"horizontal""vertical"
—The orientation of the tab list.
itemsTabComponentProps[]—The items of the tab list. When provided, tabs are rendered automatically via the render function in children.
fullWidthboolean—Whether the tab list is full width.
Props from React Aria Components (9)
Tabs.List inherited props
PropTypeDefaultDescription
childrenReactNode | ((item: TabComponentProps) => ReactNode)—The contents of the collection.
dependenciesreadonly any[]—Values that should invalidate the item cache when using dynamic collections.
styleStyleOrFunction<TabListRenderProps>—The inline style for the element. A function may be provided to compute the style based on component state.
classNameClassNameOrFunction<TabListRenderProps>—The CSS className for the element. A function may be provided to compute the class based on component state.
renderDOMRenderFunction<"div", TabListRenderProps>—Overrides the default DOM element with a custom render function. This allows rendering existing components with built-in styles and behaviors such as router links, animation libraries, and pre-styled components.Requirements:
  • You must render the expected element type (e.g. if <button> is expected, you cannot render an <a>).
  • Only a single root DOM element can be rendered (no fragments).
  • You must pass through props and ref to the underlying DOM element, merging with your own prop as appropriate.
aria-describedbystring—Identifies the element (or elements) that describes the object.
aria-detailsstring—Identifies the element (or elements) that provide a detailed, extended description for the object.
aria-labelstring—Defines a string value that labels the current element.
aria-labelledbystring—Identifies the element (or elements) that labels the current element.

Also accepts the global HTML attributes (dir, lang, hidden, inert, translate), all standard React DOM event handlers.

Tabs.Panel

Renders React Aria’s TabPanel — all of its props are supported.

Tabs.Panel props
PropTypeDefaultDescription
idKey—The unique id of the tab.
shouldForceMountbooleanfalseWhether to mount the tab panel in the DOM even when it is not currently selected. Inactive tab panels are inert and cannot be interacted with. They must be styled appropriately so this is clear to the user visually.
Styling (4)
Tabs.Panel styling props
PropTypeDefaultDescription
styleStyleOrFunction<TabPanelRenderProps>—The inline style for the element. A function may be provided to compute the style based on component state.
childrenChildrenOrFunction<TabPanelRenderProps>—The children of the component. A function may be provided to alter the children based on component state.
classNameClassNameOrFunction<TabPanelRenderProps>—The CSS className for the element. A function may be provided to compute the class based on component state.
renderDOMRenderFunction<"div", TabPanelRenderProps>—Overrides the default DOM element with a custom render function. This allows rendering existing components with built-in styles and behaviors such as router links, animation libraries, and pre-styled components.Requirements:
  • You must render the expected element type (e.g. if <button> is expected, you cannot render an <a>).
  • Only a single root DOM element can be rendered (no fragments).
  • You must pass through props and ref to the underlying DOM element, merging with your own prop as appropriate.
Accessibility (4)
Tabs.Panel accessibility props
PropTypeDefaultDescription
aria-describedbystring—Identifies the element (or elements) that describes the object.
aria-detailsstring—Identifies the element (or elements) that provide a detailed, extended description for the object.
aria-labelstring—Defines a string value that labels the current element.
aria-labelledbystring—Identifies the element (or elements) that labels the current element.

Also accepts the global HTML attributes (dir, lang, hidden, inert, translate), all standard React DOM event handlers.

FAQs

Please refer to our frequently asked questions page for more.

Set type on Tabs.List. Horizontal tabs accept "button-brand", "button-gray", "button-border", "button-minimal" and "underline". Vertical tabs accept the same button types plus "line" in place of "underline". The default is "button-brand".

Pass orientation="vertical" to Tabs. Tabs.List reads the orientation from it and stacks the tabs in a column, so you don't need to set it twice. Use type="line" for the vertical equivalent of the underline style.

Pass selectedKey and onSelectionChange to Tabs, where the key is the id of a Tabs.Item. For an uncontrolled tab group, use defaultSelectedKey instead. Each Tabs.Panel is matched to its tab by the same id.

Set size on Tabs.List to "sm" or "md". The default is "sm". Add fullWidth to Tabs.List to stretch every tab with flex-1 so they share the available width equally.

Yes. Pass badge (a string or number) and icon (a component or element) to Tabs.Item. The badge is styled hidden md:flex, so it is not visible below the md breakpoint. The "underline", "line" and "button-brand" types render it as a pill that turns brand-colored when the tab is hovered or selected, while the other types render a gray modern badge that keeps its color in every state.

Tabs sets React Aria's keyboardActivation to "manual" by default, so the arrow keys move focus between tabs and Enter or Space selects the focused tab. Pass keyboardActivation="automatic" to Tabs if you want a tab to be selected as soon as it receives focus.

The examples on this page hide the tabs below the md breakpoint with max-md:hidden and show a NativeSelect instead, wired to the same selectedKey state. Copy that pattern if your tab list is too wide for small screens, or drop the select if your tabs fit.