'use client'
import { Tabs } from '@saas-ui/react'
import { LuFolder, LuSquareCheck, LuUser } from 'react-icons/lu'
export const TabsBasic = () => {
return (
<Tabs.Root defaultValue="members">
<Tabs.List>
<Tabs.Trigger value="members">
<LuUser />
Members
</Tabs.Trigger>
<Tabs.Trigger value="projects">
<LuFolder />
Projects
</Tabs.Trigger>
<Tabs.Trigger value="tasks">
<LuSquareCheck />
Settings
</Tabs.Trigger>
</Tabs.List>
<Tabs.Content value="members">Manage your team members</Tabs.Content>
<Tabs.Content value="projects">Manage your projects</Tabs.Content>
<Tabs.Content value="tasks">
Manage your tasks for freelancers
</Tabs.Content>
</Tabs.Root>
)
}
import { Tabs } from '@saas-ui/react/tabs'
<Tabs.Root>
<Tabs.List>
<Tabs.Trigger />
<Tabs.Indicator />
</Tabs.List>
<Tabs.Content />
</Tabs.Root>
Use the variant
prop to change the visual style of the tabs.
import { For, SimpleGrid } from '@chakra-ui/react'
import { Tabs } from '@saas-ui/react'
import { LuFolder, LuSquareCheck, LuUser } from 'react-icons/lu'
export const TabsWithVariants = () => {
return (
<SimpleGrid columns={2} gap="14" width="full">
<For each={['line', 'subtle', 'enclosed', 'outline', 'plain']}>
{(variant) => (
<Tabs.Root key={variant} defaultValue="members" variant={variant}>
<Tabs.List>
<Tabs.Trigger value="members">
<LuUser />
Members
</Tabs.Trigger>
<Tabs.Trigger value="projects">
<LuFolder />
Projects
</Tabs.Trigger>
<Tabs.Trigger value="tasks">
<LuSquareCheck />
Settings
</Tabs.Trigger>
</Tabs.List>
<Tabs.Content value="members">
Manage your team members
</Tabs.Content>
<Tabs.Content value="projects">Manage your projects</Tabs.Content>
<Tabs.Content value="tasks">
Manage your tasks for freelancers
</Tabs.Content>
</Tabs.Root>
)}
</For>
</SimpleGrid>
)
}
Use the lazyMount
and/or unmountOnExit
prop to only render the tab content
when it is active. This can be useful for performance optimization.
'use client'
import { useEffect, useState } from 'react'
import { Tabs } from '@saas-ui/react'
export const TabsLazyMounted = () => {
return (
<Tabs.Root lazyMount unmountOnExit defaultValue="tab-1">
<Tabs.List>
<Tabs.Trigger value="tab-1">Tab 1</Tabs.Trigger>
<Tabs.Trigger value="tab-2">Tab 2</Tabs.Trigger>
<Tabs.Trigger value="tab-3">Tab 3</Tabs.Trigger>
</Tabs.List>
<Tabs.Content value="tab-1">
Tab 1: Content <TickValue />
</Tabs.Content>
<Tabs.Content value="tab-2">
Tab 2: Content <TickValue />
</Tabs.Content>
<Tabs.Content value="tab-3">
Tab 3: Content <TickValue />
</Tabs.Content>
</Tabs.Root>
)
}
const TickValue = () => {
const [value, setValue] = useState(0)
useEffect(() => {
const intervalId = window.setInterval(() => {
setValue((v) => v + 1)
}, 1000)
return () => {
window.clearInterval(intervalId)
}
}, [])
return (
<span style={{ fontWeight: 'bold', color: 'tomato', padding: 4 }}>
{value}
</span>
)
}
Render the Tabs.Indicator
component to display a visual indicator of the
active tab.
'use client'
import { Tabs } from '@saas-ui/react'
import { LuFolder, LuSquareCheck, LuUser } from 'react-icons/lu'
export const TabsWithIndicator = () => {
return (
<Tabs.Root defaultValue="members" variant="plain">
<Tabs.List bg="bg.muted" rounded="l3" p="1">
<Tabs.Trigger value="members">
<LuUser />
Members
</Tabs.Trigger>
<Tabs.Trigger value="projects">
<LuFolder />
Projects
</Tabs.Trigger>
<Tabs.Trigger value="tasks">
<LuSquareCheck />
Settings
</Tabs.Trigger>
<Tabs.Indicator rounded="l2" />
</Tabs.List>
<Tabs.Content value="members">Manage your team members</Tabs.Content>
<Tabs.Content value="projects">Manage your projects</Tabs.Content>
<Tabs.Content value="tasks">
Manage your tasks for freelancers
</Tabs.Content>
</Tabs.Root>
)
}
Pass the asChild
to the Tabs.Trigger
component to render a link as a tab.
When a tab is clicked, the link will be navigated to.
'use client'
import { Link } from '@chakra-ui/react'
import { Tabs } from '@saas-ui/react'
export const TabsWithLinks = () => {
return (
<Tabs.Root defaultValue="members">
<Tabs.List>
<Tabs.Trigger value="members" asChild>
<Link unstyled href="#members">
Members
</Link>
</Tabs.Trigger>
<Tabs.Trigger value="projects" asChild>
<Link unstyled href="#projects">
Projects
</Link>
</Tabs.Trigger>
</Tabs.List>
<Tabs.Content value="members">Manage your team members</Tabs.Content>
<Tabs.Content value="projects">Manage your projects</Tabs.Content>
</Tabs.Root>
)
}
Use the fitted
prop to make the tabs fit the width of the container.
'use client'
import { Tabs } from '@saas-ui/react'
export const TabsWithFitted = () => {
return (
<Tabs.Root variant="enclosed" maxW="md" fitted defaultValue={'tab-1'}>
<Tabs.List>
<Tabs.Trigger value="tab-1">Tab 1</Tabs.Trigger>
<Tabs.Trigger value="tab-2">Tab 2</Tabs.Trigger>
<Tabs.Trigger value="tab-3">Tab 3</Tabs.Trigger>
</Tabs.List>
</Tabs.Root>
)
}
Use the value
and onValueChange
prop to control the active tab.
'use client'
import { useState } from 'react'
import { Tabs } from '@saas-ui/react'
export const TabsControlled = () => {
const [value, setValue] = useState<string | null>('first')
return (
<Tabs.Root value={value} onValueChange={(e) => setValue(e.value)}>
<Tabs.List>
<Tabs.Trigger value="first">First tab</Tabs.Trigger>
<Tabs.Trigger value="second">Second tab</Tabs.Trigger>
</Tabs.List>
<Tabs.Content value="first">First panel</Tabs.Content>
<Tabs.Content value="second">Second panel</Tabs.Content>
</Tabs.Root>
)
}
Set the disabled
prop on the Tabs.Trigger
component to disable a tab.
'use client'
import { Tabs } from '@saas-ui/react'
import { LuFolder, LuSquareCheck, LuUser } from 'react-icons/lu'
export const TabsWithDisabledTab = () => {
return (
<Tabs.Root defaultValue="members">
<Tabs.List>
<Tabs.Trigger value="members">
<LuUser />
Members
</Tabs.Trigger>
<Tabs.Trigger value="projects" disabled>
<LuFolder />
Projects
</Tabs.Trigger>
<Tabs.Trigger value="tasks">
<LuSquareCheck />
Settings
</Tabs.Trigger>
</Tabs.List>
{/* content */}
</Tabs.Root>
)
}
By default, the tabs are selected when the arrow keys are pressed. Disable this
behavior by setting the activationBehavior
prop to manual
.
In this mode, the tabs will only be selected when clicked or the enter key is pressed.
'use client'
import { Tabs } from '@saas-ui/react'
import { LuFolder, LuSquareCheck, LuUser } from 'react-icons/lu'
export const TabsWithManualActivation = () => {
return (
<Tabs.Root defaultValue="members" activationMode="manual">
<Tabs.List>
<Tabs.Trigger value="members">
<LuUser />
Members
</Tabs.Trigger>
<Tabs.Trigger value="projects" disabled>
<LuFolder />
Projects
</Tabs.Trigger>
<Tabs.Trigger value="tasks">
<LuSquareCheck />
Settings
</Tabs.Trigger>
</Tabs.List>
{/* content */}
</Tabs.Root>
)
}
Here's an example of how to dynamically add and remove tabs.
Tab Content 1
Dolore ex esse laboris elit magna esse sunt. Pariatur in veniam Lorem est occaecat do magna nisi mollit ipsum sit adipisicing fugiat ex. Pariatur ullamco exercitation ea qui adipisicing. Id cupidatat aute id ut excepteur exercitation magna pariatur. Mollit irure irure reprehenderit pariatur eiusmod proident Lorem deserunt duis cillum mollit.
Tab Content 2
Dolore ex esse laboris elit magna esse sunt. Pariatur in veniam Lorem est occaecat do magna nisi mollit ipsum sit adipisicing fugiat ex. Pariatur ullamco exercitation ea qui adipisicing. Id cupidatat aute id ut excepteur exercitation magna pariatur. Mollit irure irure reprehenderit pariatur eiusmod proident Lorem deserunt duis cillum mollit.
Tab Content 3
Dolore ex esse laboris elit magna esse sunt. Pariatur in veniam Lorem est occaecat do magna nisi mollit ipsum sit adipisicing fugiat ex. Pariatur ullamco exercitation ea qui adipisicing. Id cupidatat aute id ut excepteur exercitation magna pariatur. Mollit irure irure reprehenderit pariatur eiusmod proident Lorem deserunt duis cillum mollit.
Tab Content 4
Dolore ex esse laboris elit magna esse sunt. Pariatur in veniam Lorem est occaecat do magna nisi mollit ipsum sit adipisicing fugiat ex. Pariatur ullamco exercitation ea qui adipisicing. Id cupidatat aute id ut excepteur exercitation magna pariatur. Mollit irure irure reprehenderit pariatur eiusmod proident Lorem deserunt duis cillum mollit.
'use client'
import { useState } from 'react'
import { Button, Heading, Text } from '@chakra-ui/react'
import { CloseButton, Tabs } from '@saas-ui/react'
import { LuPlus } from 'react-icons/lu'
interface Item {
id: string
title: string
content: React.ReactNode
}
const items: Item[] = [
{ id: '1', title: 'Tab', content: 'Tab Content' },
{ id: '2', title: 'Tab', content: 'Tab Content' },
{ id: '3', title: 'Tab', content: 'Tab Content' },
{ id: '4', title: 'Tab', content: 'Tab Content' },
]
const uuid = () => {
return Math.random().toString(36).substring(2, 15)
}
export const TabsWithDynamicAdd = () => {
const [tabs, setTabs] = useState<Item[]>(items)
const [selectedTab, setSelectedTab] = useState<string | null>(items[0].id)
const addTab = () => {
const newTabs = [...tabs]
const uid = uuid()
newTabs.push({
id: uid,
title: `Tab`,
content: `Tab Body`,
})
setTabs(newTabs)
setSelectedTab(newTabs[newTabs.length - 1].id)
}
const removeTab = (id: string) => {
if (tabs.length > 1) {
const newTabs = [...tabs].filter((tab) => tab.id !== id)
setTabs(newTabs)
}
}
return (
<Tabs.Root
value={selectedTab}
variant="outline"
size="sm"
onValueChange={(e) => setSelectedTab(e.value)}
>
<Tabs.List flex="1 1 auto">
{tabs.map((item) => (
<Tabs.Trigger value={item.id} key={item.id}>
{item.title}{' '}
<CloseButton
as="span"
role="button"
size="2xs"
me="-2"
onClick={(e) => {
e.stopPropagation()
removeTab(item.id)
}}
/>
</Tabs.Trigger>
))}
<Button
alignSelf="center"
ms="2"
size="2xs"
variant="ghost"
onClick={addTab}
>
<LuPlus /> Add Tab
</Button>
</Tabs.List>
<Tabs.ContentGroup>
{tabs.map((item) => (
<Tabs.Content value={item.id} key={item.id}>
<Heading size="xl" my="6">
{item.content} {item.id}
</Heading>
<Text>
Dolore ex esse laboris elit magna esse sunt. Pariatur in veniam
Lorem est occaecat do magna nisi mollit ipsum sit adipisicing
fugiat ex. Pariatur ullamco exercitation ea qui adipisicing. Id
cupidatat aute id ut excepteur exercitation magna pariatur. Mollit
irure irure reprehenderit pariatur eiusmod proident Lorem deserunt
duis cillum mollit.
</Text>
</Tabs.Content>
))}
</Tabs.ContentGroup>
</Tabs.Root>
)
}
Prop | Default | Type |
---|---|---|
activationMode | '\'automatic\'' | 'manual' | 'automatic' The activation mode of the tabs. Can be `manual` or `automatic` - `manual`: Tabs are activated when clicked or press `enter` key. - `automatic`: Tabs are activated when receiving focus |
lazyMount | false | boolean Whether to enable lazy mounting |
loopFocus | true | boolean Whether the keyboard navigation will loop from last tab to first, and vice versa. |
orientation | '\'horizontal\'' | 'horizontal' | 'vertical' The orientation of the tabs. Can be `horizontal` or `vertical` - `horizontal`: only left and right arrow key navigation will work. - `vertical`: only up and down arrow key navigation will work. |
unmountOnExit | false | boolean Whether to unmount on exit. |
colorPalette | 'gray' | 'gray' | 'red' | 'orange' | 'yellow' | 'green' | 'teal' | 'blue' | 'cyan' | 'purple' | 'pink' | 'accent' The color palette of the component |
size | 'md' | 'sm' | 'md' | 'lg' The size of the component |
variant | 'line' | 'line' | 'subtle' | 'enclosed' | 'outline' | 'plain' The variant of the component |
asChild | boolean Use the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. | |
composite | boolean Whether the tab is composite | |
defaultValue | string The initial value of the tabs when it is first rendered. Use when you do not need to control the state of the tabs. | |
id | string The unique identifier of the machine. | |
ids | Partial<{
root: string
trigger: string
list: string
content: string
indicator: string
}> The ids of the elements in the tabs. Useful for composition. | |
onFocusChange | (details: FocusChangeDetails) => void Callback to be called when the focused tab changes | |
onValueChange | (details: ValueChangeDetails) => void Callback to be called when the selected/active tab changes | |
translations | IntlTranslations Specifies the localized strings that identifies the accessibility elements and their states | |
value | string The selected tab id | |
fitted | 'true' | 'false' The fitted of the component | |
justify | 'start' | 'center' | 'end' The justify of the component |
Prop | Default | Type |
---|---|---|
value * | string The value of the tab | |
asChild | boolean Use the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. | |
disabled | boolean Whether the tab is disabled |
Prop | Default | Type |
---|---|---|
value * | string The value of the tab | |
asChild | boolean Use the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |