Tab List
- Stable
- WCAG 2.2 evidence
- RTL
The row of tabs inside Tabs. Built on React Aria TabList: role tablist with
aria-orientation; one tab is in the tab order, the arrow keys move between tabs (mirrored in right-to-left locales), Home
and End jump to the ends, and Tab leaves the list for the panel (WCAG 2.1.1, 4.1.2). It passes its variant to the tabs. Many tabs scroll horizontally inside the list, with the native scrollbar as the visible affordance, so the page reflows at
320 px (1.4.10) and the focused tab is scrolled into view (2.4.11). Figma advises a menu or vertical tabs beyond 7 tabs. Consumer duties: a name for the list and labels that match the panels.
import { TabList } from "@nexera-ui/react";- 5
- examples
- 9
- props
- 1
- live controls
- 1
- platform
- 5
- WCAG criteria
- 6
- blocks use it
Try every prop. Copy the code.
Change the props and the code updates. Check light and dark, LTR and RTL, and phone width.
import { TabList } from "@nexera-ui/react";
<TabList />Examples 4
The same examples as Storybook, rendered live. Open Code to copy one.
Variants
The three Figma variants. Pill hugs its tabs; Underline and Enclosed span the container.
import { Tab, TabList, TabPanel, Tabs } from "@nexera-ui/react";
const variants = ["underline", "pill", "enclosed"] as const;
const sections = ["Overview", "Documents", "Time off", "Payroll", "Benefits"] as const;
export function Variants() {
return (
<div className="flex flex-col gap-6">
{variants.map((variant) => (
<Tabs key={variant} defaultSelectedKey="Overview">
<TabList aria-label={`Employee (${variant})`} variant={variant}>
{sections.map((section) => (
<Tab key={section} id={section} label={section} />
))}
</TabList>
<TabPanel id="Overview" className="sr-only">
Overview panel
</TabPanel>
</Tabs>
))}
</div>
);
}
Overflow
More tabs than fit: the list scrolls horizontally inside itself (the scrollbar is the visible affordance) and the focused tab is scrolled into view, so the page still reflows at 320 px. Figma advises a menu or vertical tabs beyond 7 tabs.
import { Tab, TabList, TabPanel, Tabs } from "@nexera-ui/react";
const variants = ["underline", "pill", "enclosed"] as const;
export function Overflow() {
return (
<div className="flex max-w-sm flex-col gap-6">
{variants.map((variant) => (
<Tabs key={variant} defaultSelectedKey="Overview">
<TabList aria-label={`Employee records (${variant})`} variant={variant}>
{[...sections, "Performance", "Training", "Assets", "Notes"].map((section) => (
<Tab key={section} id={section} label={section} />
))}
</TabList>
<TabPanel id="Overview" className="sr-only">
Overview panel
</TabPanel>
</Tabs>
))}
</div>
);
}
Manual activation
keyboardActivation="manual" on Tabs: the arrow keys move focus, Enter or Space shows the panel (for slow panels).
import { Tab, TabList, TabPanel, Tabs } from "@nexera-ui/react";
const sections = ["Overview", "Documents", "Time off", "Payroll", "Benefits"] as const;
export function ManualActivation() {
return (
<Tabs defaultSelectedKey="Overview" keyboardActivation="manual">
<TabList aria-label="Reports" variant="pill">
{sections.slice(0, 3).map((section) => (
<Tab key={section} id={section} label={section} />
))}
</TabList>
{sections.slice(0, 3).map((section) => (
<TabPanel key={section} id={section} className="py-4">
{section} report.
</TabPanel>
))}
</Tabs>
);
}
Vertical
<Tabs orientation="vertical"> with VerticalTabs: a column beside the panel; up and down arrows move between tabs.
import { TabList, TabPanel, Tabs, VerticalTab } from "@nexera-ui/react";
import { LuBell, LuLock, LuUser } from "react-icons/lu";
export function Vertical() {
return (
<Tabs orientation="vertical" defaultSelectedKey="profile" className="flex-wrap gap-6">
<TabList aria-label="Settings">
<VerticalTab id="profile" label="Profile" icon={<LuUser />} />
<VerticalTab id="notifications" label="Notifications" icon={<LuBell />} />
<VerticalTab id="security" label="Security" icon={<LuLock />} />
</TabList>
<TabPanel id="profile">Name, photo and contact details.</TabPanel>
<TabPanel id="notifications">Email and push preferences.</TabPanel>
<TabPanel id="security">Password and two-step verification.</TabPanel>
</Tabs>
);
}
Props 9
Press "Try it" on a card to load that prop into the playground.
9 props shown
variantNexera"underline" | "pill" | "enclosed"Look of the list and of every Tab in it. A tab's own variant wins. Ignored by a vertical list
(<Tabs orientation="vertical">), which is a plain column of VerticalTabs.
classNameNexerastringExtra classes, merged last so they win over the defaults.
styleNexeraCSSPropertiesInline style.
aria-labelNexerastringAccessible name of the tab list ("Employee sections"). Translate it.
Accessible name; aria-labelledby wins when both are set.
aria-labelledbyNexerastringId(s) of element(s) that name the list; wins over aria-label.
Id(s) of the visible element(s) that name the list, for example the page heading.
childrenReact AriaReactNode | ((item: T) => ReactNode)The contents of the collection.
itemsReact AriaIterable<T>Item objects in the collection.
dependenciesReact Ariareadonly any[]Values that should invalidate the item cache when using dynamic collections.
aria-describedbyReact AriastringIdentifies the element (or elements) that describes the object.
* Required. React Aria props shown are the ones most apps use; the component accepts the rest of its React Aria props too.
Accessible by default.
Built on React Aria, and covered by the WCAG 2.2 evidence generated on every build.
WCAG 2.2 evidence
3 direct · 2 supporting- 1.3.1Info and RelationshipsLevel A · tested directly
- 1.4.10ReflowLevel AA · supporting test
- 2.1.1KeyboardLevel A · tested directly
- 2.4.11Focus Not Obscured (Minimum)Level AA · supporting test
- 4.1.2Name, Role, ValueLevel A · tested directly
Fits any width.
Nexera components respond to the space they are given. Drag the corner of the frame, or pick a width.
Styling hooks
Pass className to add Tailwind classes (merged last). State is exposed as data attributes, so you can style it with variants like data-pressed:.
<TabList className="shadow-sm" />Used in blocks
- Top bar with tabsApp shells and navigation
- Settings layoutApp shells and navigation
- Notification centreMessaging and collaboration
- Approvals inboxWork and projects
- Image editorMedia and content
- Photo editorMobile patterns
Related components
- BreadcrumbShows where the current page sits in the hierarchy and links back to each level.
- BreadcrumbItemOne level of a `Breadcrumb` trail; use it only inside `Breadcrumb`.
- CursorPagerA previous and next pair for data without stable page numbers, such as an activity log or a cursor API.
- FABThe main action of a mobile screen: a floating button with a `nav/active-bg` fill and a large shadow.
- FeedStatusThe status line at the bottom of an infinite feed or a lazy list: "Loading more", "You have reached the end" or "Could not load more" with a retry action.
- JumpToPageA small "Go to page [48] of 120" control for long paged lists.
- NavigationBarThe bottom bar of a mobile layout: a named `nav` landmark with a list of three to five `NavItem`s.
- NavItemOne destination or action of a `NavigationBar`.