dotUI
dotUI
beta
  1. Components
  2. Navigation
  3. Tabs

Tabs

Tabs organize content into multiple sections and allow users to navigate between them

import { Tabs, TabList, TabPanel, Tab } from "@/lib/components/core/default/tabs";

function Demo() {
  return (
    <Tabs>
      <TabList>
        <Tab id="overview">Overview</Tab>
        <Tab id="usage">Usage</Tab>
        <Tab id="settings">Settings</Tab>
      </TabList>
      <TabPanel id="overview"> You can view all your projects here. </TabPanel>
      <TabPanel id="usage"> You can view your usage here. </TabPanel>
      <TabPanel id="settings"> You can view your settings here. </TabPanel>
    </Tabs>
  );
}

Installation

Install the following dependencies:

npm install react-aria-components

Copy and paste the following code into your project.

"use client";

import * as React from "react";
import {
  Tabs as AriaTabs,
  TabList as AriaTabList,
  Tab as AriaTab,
  TabPanel as AriaTabPanel,
  type TabsProps as AriaTabsProps,
  type TabListProps as AriaTabListProps,
  type TabProps as AriaTabProps,
  type TabPanelProps as AriaTabPanelProps,
  composeRenderProps,
} from "react-aria-components";
import { tv } from "tailwind-variants";
import { focusRing } from "@/lib/utils/styles";

const tabsStyles = tv({
  slots: {
    root: "flex flex-col orientation-vertical:flex-row [&_[role=tabpanel]]:orientation-horizontal:mt-2 [&_[role=tabpanel]]:orientation-vertical:ml-2",
    list: "flex orientation-horizontal:overflow-x-auto orientation-horizontal:whitespace-nowrap orientation-horizontal:items-center orientation-horizontal:border-b orientation-vertical:flex-col orientation-vertical:border-r [&_[role=tab]]:orientation-horizontal:border-b-[3px] [&_[role=tab]]:orientation-vertical:border-r-[3px]",
    tab: [
      "cursor-pointer text-center text-fg-muted border-transparent selected:border-border-focus selected:text-fg -mb-px px-2 py-2 text-sm font-medium outline-none transition-colors disabled:text-fg-disabled disabled:cursor-default disabled:selected:border-border-disabled",
      "[&>span]:py-1 [&>span]:px-1.5 [&>span]:rounded-md [&>span]:border-2 [&>span]:border-transparent [&>span]:focus-visible:border-border-focus",
    ],
    panel: [focusRing(), "rounded"],
  },
});

interface TabsProps extends Omit<AriaTabsProps, "className"> {
  className?: string;
}
const Tabs = ({ className, ...props }: TabsProps) => {
  const { root } = tabsStyles();
  return <AriaTabs className={root({ className })} {...props} />;
};

interface TabListProps<T> extends Omit<AriaTabListProps<T>, "className"> {
  className?: string;
}
const TabList = <T extends object>({ className, ...props }: TabListProps<T>) => {
  const { list } = tabsStyles();
  return (
    <AriaTabList {...props} className={list({ className })} style={{ scrollbarWidth: "none" }} />
  );
};

interface TabProps extends Omit<AriaTabProps, "className"> {
  className?: string;
}
const Tab = ({ className, ...props }: TabProps) => {
  const { tab } = tabsStyles();
  return (
    <AriaTab className={tab({ className })} {...props}>
      {composeRenderProps(props.children, (children) => (
        <span>{children}</span>
      ))}
    </AriaTab>
  );
};

interface TabPanelProps extends Omit<AriaTabPanelProps, "className"> {
  className?: string;
}
const TabPanel = ({ className, ...props }: TabPanelProps) => {
  const { panel } = tabsStyles();
  return <AriaTabPanel className={panel({ className })} {...props} />;
};

export type { TabsProps, TabListProps, TabProps, TabPanelProps };
export { Tabs, TabList, Tab, TabPanel };

Update the import paths to match your project setup.

Usage

Use Tabs to organize content into multiple sections and allow users to navigate between them.

  • The content under the set of tabs should be related and form a coherent unit.

Options

Orientation

Use the orientation prop to set the orientation of the tabs.

import { Tabs, TabList, TabPanel, Tab } from "@/lib/components/core/default/tabs";

function Demo() {
  return (
    <Tabs orientation="vertical">
      <TabList>
        <Tab id="overview">Overview</Tab>
        <Tab id="usage">Usage</Tab>
        <Tab id="settings">Settings</Tab>
      </TabList>
      <TabPanel id="overview">You can view all your projects here. </TabPanel>
      <TabPanel id="usage"> You can view your usage here. </TabPanel>
      <TabPanel id="settings"> You can view your settings here. </TabPanel>
    </Tabs>
  );
}

Disabled

Use the isDisabled prop to disable the tabs.

import { Tabs, TabList, TabPanel, Tab } from "@/lib/components/core/default/tabs";

function Demo() {
  return (
    <Tabs isDisabled>
      <TabList>
        <Tab id="overview">Overview</Tab>
        <Tab id="usage">Usage</Tab>
        <Tab id="settings">Settings</Tab>
      </TabList>
      <TabPanel id="overview"> You can view all your projects here. </TabPanel>
      <TabPanel id="usage"> You can view your usage here. </TabPanel>
      <TabPanel id="settings"> You can view your settings here. </TabPanel>
    </Tabs>
  );
}

An individual Tab can also be disabled with the isDisabled prop.

import { Tabs, TabList, TabPanel, Tab } from "@/lib/components/core/default/tabs";

function Demo() {
  return (
    <Tabs>
      <TabList>
        <Tab id="overview">Overview</Tab>
        <Tab id="usage">Usage</Tab>
        <Tab id="settings" isDisabled>
          Settings
        </Tab>
      </TabList>
      <TabPanel id="overview"> You can view all your projects here. </TabPanel>
      <TabPanel id="usage"> You can view your usage here. </TabPanel>
      <TabPanel id="settings"> You can view your settings here. </TabPanel>
    </Tabs>
  );
}

Keyboard activation

Prevent keyboard activation of tabs by setting keyboardActivation prop to 'manual'.

import { Tabs, TabList, TabPanel, Tab } from "@/lib/components/core/default/tabs";

function Demo() {
  return (
    <Tabs keyboardActivation="manual">
      <TabList>
        <Tab id="overview">Overview</Tab>
        <Tab id="usage">Usage</Tab>
        <Tab id="settings">Settings</Tab>
      </TabList>
      <TabPanel id="overview"> You can view all your projects here. </TabPanel>
      <TabPanel id="usage"> You can view your usage here. </TabPanel>
      <TabPanel id="settings"> You can view your settings here. </TabPanel>
    </Tabs>
  );
}

Controlled

Use the selectedKey prop to control the selected tab.

"use client";

import React from "react";
import type { Key } from "react-aria-components";
import { Tabs, TabList, TabPanel, Tab } from "@/lib/components/core/default/tabs";

function Demo() {
  const [selectedTab, setSelectedTab] = React.useState<Key>("overview");
  return (
    <div className="flex flex-col items-center gap-6">
      <Tabs selectedKey={selectedTab} onSelectionChange={setSelectedTab}>
        <TabList>
          <Tab id="overview">Overview</Tab>
          <Tab id="usage">Usage</Tab>
          <Tab id="settings">Settings</Tab>
        </TabList>
        <TabPanel id="overview"> You can view all your projects here. </TabPanel>
        <TabPanel id="usage"> You can view your usage here. </TabPanel>
        <TabPanel id="settings"> You can view your settings here. </TabPanel>
      </Tabs>
      <p className="text-sm text-fg-muted">
        Selected tab: <span className="font-bold text-fg">{selectedTab}</span>
      </p>
    </div>
  );
}

API Reference

Tabs

PropTypeDefaultDescription
isDisabled
boolean
-
Whether the TabList is disabled. Shows that a selection exists, but is not available in that circumstance.
disabledKeys
Iterable<Key>
-
The item keys that are disabled. These items cannot be selected, focused, or otherwise interacted with.
selectedKey
Key | null
-
The currently selected key in the collection (controlled).
defaultSelectedKey
Key
-
The initial selected key in the collection (uncontrolled).
keyboardActivation
'automatic' | 'manual'
'automatic
Whether tabs are activated automatically on focus or manually.
orientation
'horizontal' | 'vertical'
'horizontal
The orientation of the tabs.
children
ReactNode | (values: TabsRenderProps & {defaultChildren: ReactNode | undefined}) => ReactNode
-
The children of the component. A function may be provided to alter the children based on component state.
className
string
-
The CSS className for the element.
style
CSSProperties | (values: TabsRenderProps & {defaultStyle: CSSProperties}) => CSSProperties
-
The inline style for the element. A function may be provided to compute the style based on component state.
EventTypeDescription
onSelectionChange
(key: Key) => void
Handler that is called when the selection changes.
Data attributeDescription
[data-orientation="horizontal | vertical"]
The orientation of the tabs.

TabList

PropTypeDefaultDescription
dependencies
any[]
-
Values that should invalidate the item cache when using dynamic collections.
items
Iterable<T>
-
Item objects in the collection.
children
ReactNode | (values: TabListRenderProps & {defaultChildren: ReactNode | undefined}) => ReactNode
-
The children of the component. A function may be provided to alter the children based on component state.
className
string
-
The CSS className for the element.
style
CSSProperties | (values: TabListRenderProps & {defaultStyle: CSSProperties}) => CSSProperties
-
The inline style for the element. A function may be provided to compute the style based on component state.
Data attributeDescription
[data-orientation="horizontal | vertical"]
The orientation of the tabs.

Tab

PropTypeDefaultDescription
id
Key
-
The unique id of the tab.
isDisabled
boolean
-
Whether the tab is disabled.
href
Href
-
A URL to link to.
hrefLang
string
-
Hints at the human language of the linked URL.
target
HTMLAttributeAnchorTarget
-
The target window for the link.
rel
string
-
The relationship between the linked resource and the current page.
download
boolean | string
-
Causes the browser to download the linked URL. A string may be provided to suggest a file name.
ping
string
-
A space-separated list of URLs to ping when the link is followed.
referrerPolicy
HTMLAttributeReferrerPolicy
-
How much of the referrer to send when following the link.
routerOptions
RouterOptions
-
Options for the configured client side router.
children
ReactNode | (values: TabRenderProps & {defaultChildren: ReactNode | undefined}) => ReactNode
-
The children of the component. A function may be provided to alter the children based on component state.
className
string
-
The CSS className for the element.
style
CSSProperties | (values: TabRenderProps & {defaultStyle: CSSProperties}) => CSSProperties
-
The inline style for the element. A function may be provided to compute the style based on component state.
Data attributeDescription
[data-hovered]
Whether the tab is currently hovered with a mouse.
[data-pressed]
Whether the tab is currently in a pressed state.
[data-selected]
Whether the tab is currently selected.
[data-focused]
Whether the tab is focused, either via a mouse or keyboard.
[data-focus-visible]
Whether the tab is keyboard focused.
[data-disabled]
Whether the tab is disabled.

TabPanel

PropTypeDefaultDescription
shouldForceMount
boolean
false
Whether 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.
children
ReactNode | (values: TabPanelRenderProps & {defaultChildren: ReactNode | undefined}) => ReactNode
-
The children of the component. A function may be provided to alter the children based on component state.
className
string
-
The CSS className for the element.
style
CSSProperties | (values: TabPanelRenderProps & {defaultStyle: CSSProperties}) => CSSProperties
-
The inline style for the element. A function may be provided to compute the style based on component state.
Data attributeDescription
[data-focused]
Whether the tab panel is focused, either via a mouse or keyboard.
[data-focus-visible]
Whether the tab panel is keyboard focused.
[data-inert]
Whether the tab panel is currently non-interactive. This occurs when the shouldForceMount prop is true, and the corresponding tab is not selected.

Accessibility

Keyboard interactions

KeyDescription
Tab
Moves focus into the tabs component and places focus on the selected tab item. If the tabs component is already in focus, moves focus to the next element in the page tab sequence.
ArrowRight ArrowDown
Moves focus to the next tab item. If focus is on the last tab item, moves focus to the first tab item.
ArrowLeft ArrowUp
Moves focus to the previous tab item. If focus is on the first tab item, moves focus to the last tab item.
Space Enter
Activates the tab item in focus.

Built by mehdibha. The source code is available on GitHub.