Tabs
import {Tab, Tabs} from "@qualcomm-ui/react/tabs"Examples
Horizontal
The default orientation is horizontal. The left and right arrow keys can be used to navigate between tabs.
Vertical
In vertical orientation, the up and down arrow keys are used instead.
Icons and variants
Tabs support start and end icons. Customize the variant with the iconVariant prop. Use the variant prop to change the appearance of the tab.
<Tabs.Root>
<TabContent />
</Tabs.Root>
<Tabs.Root iconVariant="filled">
<TabContent />
</Tabs.Root>
<Tabs.Root variant="contained">
<TabContent />
</Tabs.Root>
<Tabs.Root iconVariant="filled" variant="contained">
<TabContent />
</Tabs.Root>Controlled Value
The tab's active value can be controlled via the value, onValueChange, and defaultValue properties. These props follow our controlled state pattern.
Sizes
Line
The line variant supports four sizes: sm, md, lg, and xl
Contained
The contained variant supports only two sizes: sm and md
Lazy Mounted
Use the lazyMount and unmountOnExit props to control render behavior for inactive tabs.
Disabled
Disable specific tabs with the disabled prop on the <Tab.Root> component.
<Tab.Root disabled value="products">
<Tab.Button endIcon={Smartphone}>Products</Tab.Button>
</Tab.Root>URL Search Parameters
The following example demonstrates how to render tabs that sync with the URL search parameters using react-router.
Context
Use the <Tabs.Context> component to access the tabs API from JSX.
<Tabs.Context>
{(context) => (
<>
<Tabs.Panel value="tab-1">
<Button
endIcon={ChevronRight}
onClick={() => context.setValue("tab-2")}
size="sm"
variant="outline"
>
Go to next tab
</Button>
</Tabs.Panel>
<Tabs.Panel className="flex items-center gap-2" value="tab-2">
<Button
onClick={() => context.setValue("tab-1")}
size="sm"
startIcon={ChevronLeft}
variant="outline"
>
Go to prev tab
</Button>
<Button
endIcon={ChevronRight}
onClick={() => context.setValue("tab-3")}
size="sm"
variant="outline"
>
Go to next tab
</Button>
</Tabs.Panel>
<Tabs.Panel value="tab-3">
<Button
onClick={() => context.setValue("tab-2")}
size="sm"
startIcon={ChevronLeft}
variant="outline"
>
Go to previous tab
</Button>
</Tabs.Panel>
</>
)}
</Tabs.Context>Add and Remove Tabs
Lorem ipsum dolor sit amet consectetur adipiscing elit. Quisque faucibus ex sapien vitae pellentesque sem placerat. In id cursus mi pretium tellus duis convallis. Tempus leo eu aenean sed diam urna tempor. Pulvinar vivamus fringilla lacus nec metus bibendum egestas.
Lorem ipsum dolor sit amet consectetur adipiscing elit. Quisque faucibus ex sapien vitae pellentesque sem placerat. In id cursus mi pretium tellus duis convallis. Tempus leo eu aenean sed diam urna tempor. Pulvinar vivamus fringilla lacus nec metus bibendum egestas.
Lorem ipsum dolor sit amet consectetur adipiscing elit. Quisque faucibus ex sapien vitae pellentesque sem placerat. In id cursus mi pretium tellus duis convallis. Tempus leo eu aenean sed diam urna tempor. Pulvinar vivamus fringilla lacus nec metus bibendum egestas.
Lorem ipsum dolor sit amet consectetur adipiscing elit. Quisque faucibus ex sapien vitae pellentesque sem placerat. In id cursus mi pretium tellus duis convallis. Tempus leo eu aenean sed diam urna tempor. Pulvinar vivamus fringilla lacus nec metus bibendum egestas.
API
Tabs
<Tabs.Root>
| Prop | Type | Default |
|---|---|---|
The activation mode of the tabs. | | 'automatic' | "automatic" |
If true, the indicator's position change will animate when the active tab
changes. Only applies to the line variant. | boolean | true |
Determines whether tabs act as a standalone composite widget (true) or as a
non-focusable component within another widget (false). | boolean | true |
The initial selected tab value when rendered.
Use when you don't need to control the selected tab value. | string | |
Whether the active tab can be deselected when clicking on it. | boolean | |
The document's text/writing direction. | 'ltr' | 'rtl' | 'ltr' |
A root node to correctly resolve document in custom environments. i.e.,
Iframes, Electron. | () => | |
The visual style of tab icons. | | 'ghost' | 'ghost' |
When true, the component will not be rendered in the DOM until it becomes
visible or active. | boolean | false |
Whether the keyboard navigation will loop from last tab to first, and vice versa. | boolean | true |
Callback to be called when the focused tab changes | ( | |
Callback to be called when the selected/active tab changes | ( | |
The orientation of the tabs. Can be horizontal or vertical | | 'horizontal' | "horizontal" |
Allows you to replace the component's HTML element with a different tag or component. Learn more | | ReactElement | |
| 'sm' | 'md' | |
Specifies the localized strings that identifies the accessibility elements and
their states | { | |
When true, the component will be completely removed from the DOM when it
becomes inactive or hidden, rather than just being hidden with CSS. | boolean | false |
The controlled selected tab value | string | |
Governs the appearance of the tab. | | 'line' |
| 'automatic'
| 'manual'
booleanline variant.booleanstringboolean'ltr' | 'rtl'
() =>
| Node
| ShadowRoot
| Document
| 'ghost'
| 'filled'
booleanboolean(
value: string,
) => void
(
value: string,
) => void
| 'horizontal'
| 'vertical'
horizontal or vertical| ReactElement
| ((
props: object,
) => ReactElement)
| 'sm'
| 'md'
| 'lg'
| 'xl'
lg
and xl are not supported by the contained variant.{
listLabel?: string
}
booleanstring| 'line'
| 'contained'
| Attribute / Property | Value |
|---|---|
className | 'qui-tabs__root' |
data-focus | |
data-orientation | | 'horizontal' |
data-part | 'root' |
data-scope | 'tabs' |
data-size | | 'sm' |
className'qui-tabs__root'data-focusdata-orientation| 'horizontal'
| 'vertical'
data-part'root'data-scope'tabs'data-size| 'sm'
| 'md'
| 'lg'
| 'xl'
<Tabs.List>
<div> element by default.| Prop | Type |
|---|---|
id attribute. If
omitted, a unique identifier will be automatically generated for accessibility. | string |
Allows you to replace the component's HTML element with a different tag or component. Learn more | | ReactElement |
string| ReactElement
| ((
props: object,
) => ReactElement)
| Attribute / Property | Value |
|---|---|
className | 'qui-tabs__list' |
data-focus | |
data-orientation | | 'horizontal' |
data-part | 'list' |
data-scope | 'tabs' |
data-size | | 'sm' |
data-variant | | 'line' |
className'qui-tabs__list'data-focusdata-orientation| 'horizontal'
| 'vertical'
data-part'list'data-scope'tabs'data-size| 'sm'
| 'md'
| 'lg'
| 'xl'
data-variant| 'line'
| 'contained'
<Tabs.Indicator>
<div> element by
default. You only need to render a single <Tabs.Indicator> component per tab
list.<Tabs.Root>
<Tabs.List>
<Tabs.Indicator />
<Tab.Root value="tab-1">
<Tab.Button>Tab 1</Tab.Button>
</Tab.Root>
</Tabs.List>
</Tabs.Root>
| Prop | Type |
|---|---|
id attribute. If
omitted, a unique identifier will be automatically generated for accessibility. | string |
Allows you to replace the component's HTML element with a different tag or component. Learn more | | ReactElement |
string| ReactElement
| ((
props: object,
) => ReactElement)
| Attribute / Property | Value |
|---|---|
className | 'qui-tabs__indicator' |
data-animate | |
data-focusWhether any tab has the simulated focus state. | |
data-focus-visibleWhether any tab has the simulated focus-visible state. | |
data-orientation | | 'horizontal' |
data-part | 'indicator' |
data-scope | 'tabs' |
data-size | | 'sm' |
data-variant | | 'line' |
hiddenHidden for contained variant. | boolean |
style |
className'qui-tabs__indicator'data-animatedata-focusdata-focus-visibledata-orientation| 'horizontal'
| 'vertical'
data-part'indicator'data-scope'tabs'data-size| 'sm'
| 'md'
| 'lg'
| 'xl'
data-variant| 'line'
| 'contained'
hiddenbooleancontained variant.style<Tabs.Panel>
<div> element by default.| Prop | Type |
|---|---|
The value of the associated tab | string |
id attribute. If
omitted, a unique identifier will be automatically generated for accessibility. | string |
Allows you to replace the component's HTML element with a different tag or component. Learn more | | ReactElement |
stringstring| ReactElement
| ((
props: object,
) => ReactElement)
| Attribute / Property | Value |
|---|---|
className | 'qui-tabs__panel' |
data-orientation | | 'horizontal' |
data-ownedby | string |
data-part | 'panel' |
data-scope | 'tabs' |
data-selected | |
hidden | boolean |
tabIndex | -1 | 0 |
className'qui-tabs__panel'data-orientation| 'horizontal'
| 'vertical'
data-ownedbystringdata-part'panel'data-scope'tabs'data-selectedhiddenbooleantabIndex-1 | 0
Tab
<Tab.Root>
<div> element by default.stringboolean| ReactElement
| ((
props: object,
) => ReactElement)
| Attribute / Property | Value |
|---|---|
className | 'qui-tab__root' |
data-orientation | | 'horizontal' |
data-part | 'tab' |
data-scope | 'tabs' |
data-size | | 'sm' |
data-variant | | 'line' |
className'qui-tab__root'data-orientation| 'horizontal'
| 'vertical'
data-part'tab'data-scope'tabs'data-size| 'sm'
| 'md'
| 'lg'
| 'xl'
data-variant| 'line'
| 'contained'
<Tab.Button>
<button> element by
default.| Prop | Type |
|---|---|
Use the disabled prop on the parent <Tab.Root> component instead. | never |
| LucideIcon | |
id attribute. If
omitted, a unique identifier will be automatically generated for accessibility. | string |
Allows you to replace the component's HTML element with a different tag or component. Learn more | | ReactElement |
| LucideIcon |
neverdisabled prop on the parent <Tab.Root> component instead.| LucideIcon
| ReactNode
LucideIcon, the size will automatically match the size prop.
Supply as a ReactElement for additional customization.string| ReactElement
| ((
props: object,
) => ReactElement)
| Attribute / Property | Value |
|---|---|
className | 'qui-tab__button' |
data-disabled | |
data-focus | |
data-focus-visible | |
data-indicator-rendered | |
data-orientation | | 'horizontal' |
data-ownedby | string |
data-part | 'tab-button' |
data-scope | 'tabs' |
data-selected | |
data-size | | 'sm' |
data-value | string |
data-variant | | 'line' |
tabIndex | -1 | 0 |
className'qui-tab__button'data-disableddata-focusdata-focus-visibledata-indicator-rendereddata-orientation| 'horizontal'
| 'vertical'
data-ownedbystringdata-part'tab-button'data-scope'tabs'data-selecteddata-size| 'sm'
| 'md'
| 'lg'
| 'xl'
data-valuestringdata-variant| 'line'
| 'contained'
tabIndex-1 | 0
<Tab.DismissButton>
<button> element by default.| Prop | Type |
|---|---|
Allows you to replace the component's HTML element with a different tag or component. Learn more | | ReactElement |
| ReactElement
| ((
props: object,
) => ReactElement)
| Attribute / Property | Value |
|---|---|
className | 'qui-tab__dismiss-button' |
data-part | 'tab-dismiss-button' |
data-scope | 'tabs' |
data-size | | 'sm' |
className'qui-tab__dismiss-button'data-part'tab-dismiss-button'data-scope'tabs'data-size| 'sm'
| 'md'
| 'lg'
| 'xl'
<Tabs.Context>
| Prop | Type |
|---|---|
Render Prop
that provides the current TabsApi context. |
TabsApi
| Prop | Type |
|---|---|
Clears the value of the tabs. | () => void |
Set focus on the selected tab button | () => void |
The value of the tab that is currently focused. | string |
Returns the state of the tab with the given props | (props: { |
Sets the indicator rect to the tab with the given value | ( |
Sets the value of the tabs. | ( |
Synchronizes the tab index of the content element.
Useful when rendering tabs within a select or combobox | () => void |
The current value of the tabs. | string |
() => void
() => void
string(props: {
disabled?: boolean
value: string
}) => {
disabled: boolean
focused: boolean
selected: boolean
}
(
value: string,
) => void
(
value: string,
) => void
() => void
string
<div>element by default.