Tabs
Flexible navigation tool with various modes and features.
Anatomy
To set up the tabs correctly, you'll need to understand its anatomy and how we name its parts.
Each part includes a
data-partattribute to help identify them in the DOM.
Examples
Learn how to use the Tabs component in your project. Let's take a look at the
most basic example:
import { Tabs } from '@ark-ui/react'
export const Basic = () => (
  <Tabs.Root>
    <Tabs.List>
      <Tabs.Trigger value="react">React</Tabs.Trigger>
      <Tabs.Trigger value="vue">Vue</Tabs.Trigger>
      <Tabs.Trigger value="solid">Solid</Tabs.Trigger>
    </Tabs.List>
    <Tabs.Content value="react">React Content</Tabs.Content>
    <Tabs.Content value="vue">Vue Content</Tabs.Content>
    <Tabs.Content value="solid">Solid Content</Tabs.Content>
  </Tabs.Root>
)
import { Tabs } from '@ark-ui/solid'
export const Basic = () => (
  <Tabs.Root>
    <Tabs.List>
      <Tabs.Trigger value="react">React</Tabs.Trigger>
      <Tabs.Trigger value="vue">Vue</Tabs.Trigger>
      <Tabs.Trigger value="solid">Solid</Tabs.Trigger>
    </Tabs.List>
    <Tabs.Content value="react">React Content</Tabs.Content>
    <Tabs.Content value="vue">Vue Content</Tabs.Content>
    <Tabs.Content value="solid">Solid Content</Tabs.Content>
  </Tabs.Root>
)
<script setup lang="ts">
import { Tabs } from '@ark-ui/vue'
</script>
<template>
  <Tabs.Root>
    <Tabs.List>
      <Tabs.Trigger value="react">React</Tabs.Trigger>
      <Tabs.Trigger value="vue">Vue</Tabs.Trigger>
      <Tabs.Trigger value="solid">Solid</Tabs.Trigger>
    </Tabs.List>
    <Tabs.Content value="react">React Content</Tabs.Content>
    <Tabs.Content value="vue">Vue Content</Tabs.Content>
    <Tabs.Content value="solid">Solid Content</Tabs.Content>
  </Tabs.Root>
</template>
Initial Tab
To set a default tab on initial render, use the defaultValue prop:
Example not foundExample not foundExample not foundTab Indicator
To provide a visual cue for the selected tab, use the Tabs.Indicator
component:
import { Tabs } from '@ark-ui/react'
export const Indicator = () => (
  <Tabs.Root>
    <Tabs.List>
      <Tabs.Trigger value="react">React</Tabs.Trigger>
      <Tabs.Trigger value="vue">Vue</Tabs.Trigger>
      <Tabs.Trigger value="solid">Solid</Tabs.Trigger>
      <Tabs.Indicator />
    </Tabs.List>
    <Tabs.Content value="react">React Content</Tabs.Content>
    <Tabs.Content value="vue">Vue Content</Tabs.Content>
    <Tabs.Content value="solid">Solid Content</Tabs.Content>
  </Tabs.Root>
)
import { Tabs } from '@ark-ui/solid'
export const Indicator = () => (
  <Tabs.Root>
    <Tabs.List>
      <Tabs.Trigger value="react">React</Tabs.Trigger>
      <Tabs.Trigger value="vue">Vue</Tabs.Trigger>
      <Tabs.Trigger value="solid">Solid</Tabs.Trigger>
      <Tabs.Indicator />
    </Tabs.List>
    <Tabs.Content value="react">React Content</Tabs.Content>
    <Tabs.Content value="vue">Vue Content</Tabs.Content>
    <Tabs.Content value="solid">Solid Content</Tabs.Content>
  </Tabs.Root>
)
<script setup lang="ts">
import { Tabs } from '@ark-ui/vue'
</script>
<template>
  <Tabs.Root>
    <Tabs.List>
      <Tabs.Trigger value="react">React</Tabs.Trigger>
      <Tabs.Trigger value="vue">Vue</Tabs.Trigger>
      <Tabs.Trigger value="solid">Solid</Tabs.Trigger>
      <Tabs.Indicator />
    </Tabs.List>
    <Tabs.Content value="react">React Content</Tabs.Content>
    <Tabs.Content value="vue">Vue Content</Tabs.Content>
    <Tabs.Content value="solid">Solid Content</Tabs.Content>
  </Tabs.Root>
</template>
Lazy Mounting
Lazy mounting is a feature that allows the content of a tab to be rendered only
when the tab is first activated. This is useful for performance optimization,
especially when tab content is large or complex. To enable lazy mounting, use
the lazyMount prop on the Tabs.Content component.
In addition, the unmountOnExit prop can be used in conjunction with
lazyMount to unmount the tab content when the tab is deactivated, freeing up
resources. The next time the tab is activated, its content will be re-rendered.
Example not foundExample not foundExample not foundDisabled Tab
To disable a tab, simply pass the disabled prop to the Tabs.Trigger
component:
Example not foundExample not foundExample not foundControlled Tabs
To create a controlled Tabs component, manage the current selected tab using the
value prop and update it when the onValueChange event handler is called:
import { useState } from 'react'
import { Tabs } from '@ark-ui/react'
export const Controlled = () => {
  const [value, setValue] = useState<string | null>('react')
  return (
    <Tabs.Root value={value} onValueChange={(e) => setValue(e.value)}>
      <Tabs.List>
        <Tabs.Trigger value="react">React</Tabs.Trigger>
        <Tabs.Trigger value="vue">Vue</Tabs.Trigger>
        <Tabs.Trigger value="solid">Solid</Tabs.Trigger>
      </Tabs.List>
      <Tabs.Content value="react">React Content</Tabs.Content>
      <Tabs.Content value="vue">Vue Content</Tabs.Content>
      <Tabs.Content value="solid">Solid Content</Tabs.Content>
    </Tabs.Root>
  )
}
import { createSignal } from 'solid-js'
import { Tabs } from '@ark-ui/solid'
export const Controlled = () => {
  const [value, setValue] = createSignal<string | null>('react')
  return (
    <Tabs.Root value={value()} onValueChange={(e) => setValue(e.value)}>
      <Tabs.List>
        <Tabs.Trigger value="react">React</Tabs.Trigger>
        <Tabs.Trigger value="vue">Vue</Tabs.Trigger>
        <Tabs.Trigger value="solid">Solid</Tabs.Trigger>
      </Tabs.List>
      <Tabs.Content value="react">React Content</Tabs.Content>
      <Tabs.Content value="vue">Vue Content</Tabs.Content>
      <Tabs.Content value="solid">Solid Content</Tabs.Content>
    </Tabs.Root>
  )
}
<script setup lang="ts">
import { ref } from 'vue'
import { Tabs } from '@ark-ui/vue'
const value = ref('react')
</script>
<template>
  <Tabs.Root v-model="value">
    <Tabs.List>
      <Tabs.Trigger value="react">React</Tabs.Trigger>
      <Tabs.Trigger value="vue">Vue</Tabs.Trigger>
      <Tabs.Trigger value="solid">Solid</Tabs.Trigger>
    </Tabs.List>
    <Tabs.Content value="react">React Content</Tabs.Content>
    <Tabs.Content value="vue">Vue Content</Tabs.Content>
    <Tabs.Content value="solid">Solid Content</Tabs.Content>
  </Tabs.Root>
</template>
Router Controlled Tabs
When using frameworks like Next.js, Remix, or React Router, controlling the active tabs based on the URL can be useful.
To achieve this, you need to do two things:
- Set the 
valueprop to the current URL path. - Listen to the 
onValueChangeevent and update the URL path. 
Here's an example using Remix Router
import { Tabs } from '@ark-ui/react/tabs'
import { useLocation, useNavigate, Link } from '@remix-run/react'
export default function App() {
  const { pathname } = useLocation()
  const navigate = useNavigate()
  const lastPathFragment = pathname.substring(pathname.lastIndexOf('/') + 1)
  const activeTab = lastPathFragment.length > 0 ? lastPathFragment : 'homepage'
  return (
    <Tabs.Root
      value={activeTab}
      onValueChange={({ value }) => {
        navigate(`/${value === 'home' ? '' : value}`)
      }}
    >
      <Tabs.List>
        <Tabs.Trigger asChild value="home">
          <Link to="">Home</Link>
        </Tabs.Trigger>
        <Tabs.Trigger asChild value="page-1">
          <Link to="page-1">Page 1</Link>
        </Tabs.Trigger>
        <Tabs.Trigger asChild value="page-2">
          <Link to="page-2">Page 2</Link>
        </Tabs.Trigger>
      </Tabs.List>
    </Tabs.Root>
  )
}
Vertical Tabs
The default orientation of the tabs is horizontal. To change the orientation,
set the orientation prop to vertical.
import { Tabs } from '@ark-ui/react'
export const Vertical = () => (
  <Tabs.Root orientation="vertical" defaultValue="react">
    <Tabs.List>
      <Tabs.Trigger value="react">React</Tabs.Trigger>
      <Tabs.Trigger value="vue">Vue</Tabs.Trigger>
      <Tabs.Trigger value="solid">Solid</Tabs.Trigger>
    </Tabs.List>
    <Tabs.Content value="react">React Content</Tabs.Content>
    <Tabs.Content value="vue">Vue Content</Tabs.Content>
    <Tabs.Content value="solid">Solid Content</Tabs.Content>
  </Tabs.Root>
)
import { Tabs } from '@ark-ui/solid'
export const Vertical = () => (
  <Tabs.Root orientation="vertical" value="react">
    <Tabs.List>
      <Tabs.Trigger value="react">React</Tabs.Trigger>
      <Tabs.Trigger value="vue">Vue</Tabs.Trigger>
      <Tabs.Trigger value="solid">Solid</Tabs.Trigger>
    </Tabs.List>
    <Tabs.Content value="react">React Content</Tabs.Content>
    <Tabs.Content value="vue">Vue Content</Tabs.Content>
    <Tabs.Content value="solid">Solid Content</Tabs.Content>
  </Tabs.Root>
)
<script setup lang="ts">
import { ref } from 'vue'
import { Tabs } from '@ark-ui/vue'
const value = ref('react')
</script>
<template>
  <Tabs.Root v-model="value" orientation="vertical">
    <Tabs.List>
      <Tabs.Trigger value="react">React</Tabs.Trigger>
      <Tabs.Trigger value="vue">Vue</Tabs.Trigger>
      <Tabs.Trigger value="solid">Solid</Tabs.Trigger>
    </Tabs.List>
    <Tabs.Content value="react">React Content</Tabs.Content>
    <Tabs.Content value="vue">Vue Content</Tabs.Content>
    <Tabs.Content value="solid">Solid Content</Tabs.Content>
  </Tabs.Root>
</template>
Manual Activation
By default, the tab can be selected when it receives focus from either the keyboard or pointer interaction. This is called automatic tab activation.
In contrast, manual tab activation means the tab is selected with the
Enter key or by clicking on the tab.
import { Tabs } from '@ark-ui/react'
export const Manual = () => (
  <Tabs.Root activationMode="manual" defaultValue="react">
    <Tabs.List>
      <Tabs.Trigger value="react">React</Tabs.Trigger>
      <Tabs.Trigger value="vue">Vue</Tabs.Trigger>
      <Tabs.Trigger value="solid">Solid</Tabs.Trigger>
    </Tabs.List>
    <Tabs.Content value="react">React Content</Tabs.Content>
    <Tabs.Content value="vue">Vue Content</Tabs.Content>
    <Tabs.Content value="solid">Solid Content</Tabs.Content>
  </Tabs.Root>
)
import { Tabs } from '@ark-ui/solid'
export const Manual = () => (
  <Tabs.Root activationMode="manual" value="react">
    <Tabs.List>
      <Tabs.Trigger value="react">React</Tabs.Trigger>
      <Tabs.Trigger value="vue">Vue</Tabs.Trigger>
      <Tabs.Trigger value="solid">Solid</Tabs.Trigger>
    </Tabs.List>
    <Tabs.Content value="react">React Content</Tabs.Content>
    <Tabs.Content value="vue">Vue Content</Tabs.Content>
    <Tabs.Content value="solid">Solid Content</Tabs.Content>
  </Tabs.Root>
)
<script setup lang="ts">
import { ref } from 'vue'
import { Tabs } from '@ark-ui/vue'
const value = ref('react')
</script>
<template>
  <Tabs.Root v-model="value" activationMode="manual">
    <Tabs.List>
      <Tabs.Trigger value="react">React</Tabs.Trigger>
      <Tabs.Trigger value="vue">Vue</Tabs.Trigger>
      <Tabs.Trigger value="solid">Solid</Tabs.Trigger>
    </Tabs.List>
    <Tabs.Content value="react">React Content</Tabs.Content>
    <Tabs.Content value="vue">Vue Content</Tabs.Content>
    <Tabs.Content value="solid">Solid Content</Tabs.Content>
  </Tabs.Root>
</template>
API Reference
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  | 
asChild | booleanRender as a different element type.  | |
defaultValue | stringThe initial value of the tabs when it is first rendered. Use when you do not need to control the state of the tabs.  | |
id | stringThe 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.  | |
lazyMount | false | booleanWhether to enable lazy mounting  | 
loopFocus | true | booleanWhether the keyboard navigation will loop from last tab to first, and vice versa.  | 
onFocusChange | (details: FocusChangeDetails) => voidCallback to be called when the focused tab changes  | |
onValueChange | (details: ValueChangeDetails) => voidCallback to be called when the selected/active tab changes  | |
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.  | 
translations | IntlTranslationsSpecifies the localized strings that identifies the accessibility elements and their states  | |
unmountOnExit | false | booleanWhether to unmount on exit.  | 
value | stringThe selected tab id  | 
TabContent
| Prop | Default | Type | 
|---|---|---|
value | stringThe value of the tab  | |
asChild | booleanRender as a different element type.  | 
TabIndicator
| Prop | Default | Type | 
|---|---|---|
asChild | booleanRender as a different element type.  | 
TabList
| Prop | Default | Type | 
|---|---|---|
asChild | booleanRender as a different element type.  | 
TabTrigger
| Prop | Default | Type | 
|---|---|---|
value | stringThe value of the tab  | |
asChild | booleanRender as a different element type.  | |
disabled | booleanWhether the tab is disabled  |