> ## Documentation Index
> Fetch the complete documentation index at: https://docs.twenty.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Tabs

> Switch between related panels with accessible tab navigation.

`Tabs` connects each tab to a panel using a shared `value`. Keep the values unique within a root.

## Tab panels

```tsx theme={null}
import { Tabs } from 'twenty-ui/navigation';

export const RecordTabs = () => (
  <Tabs.Root defaultValue="overview">
    <Tabs.List aria-label="Record details">
      <Tabs.Tab value="overview">Overview</Tabs.Tab>
      <Tabs.Tab value="activity" badge={3}>
        Activity
      </Tabs.Tab>
    </Tabs.List>
    <Tabs.Panel value="overview">Company and contact details.</Tabs.Panel>
    <Tabs.Panel value="activity">Recent calls and emails.</Tabs.Panel>
  </Tabs.Root>
);
```

`Tabs.Tab` accepts `startIcon`, `badge`, and a `size` of `sm` or `md` (default `sm`). The active indicator is included in `Tabs.List`.

## Controlled state and manual activation

```tsx theme={null}
import { useState } from 'react';
import { Tabs } from 'twenty-ui/navigation';

export const SettingsTabs = () => {
  const [tab, setTab] = useState<string | number | null>('profile');

  return (
    <Tabs.Root value={tab} onValueChange={setTab}>
      <Tabs.List aria-label="Settings" activateOnFocus={false}>
        <Tabs.Tab value="profile">Profile</Tabs.Tab>
        <Tabs.Tab value="notifications">Notifications</Tabs.Tab>
        <Tabs.Tab value="billing" disabled>
          Billing
        </Tabs.Tab>
      </Tabs.List>
      <Tabs.Panel value="profile">Profile settings.</Tabs.Panel>
      <Tabs.Panel value="notifications">Notification settings.</Tabs.Panel>
    </Tabs.Root>
  );
};
```

With `activateOnFocus={false}`, arrow keys move focus and Enter or Space activates the focused tab. `loopFocus` defaults to `true`. Disabled tabs are skipped. Use `orientation="vertical"` on `Root` for vertical navigation.

## Parts

| Part    | Purpose                                                    |
| ------- | ---------------------------------------------------------- |
| `Root`  | Owns the active value and orientation.                     |
| `List`  | Labels and groups the tabs; includes the active indicator. |
| `Tab`   | Selects its matching panel.                                |
| `Panel` | Displays content for one value.                            |

Use `keepMounted` on a panel when its contents must remain mounted while inactive. Give the list an accessible name that describes the set of panels.

## Props

The reference is generated from the public component types. Native attributes, including accessible names and event handlers, are also accepted on parts that render elements.

### Tabs.Root

<ParamField body="Root.className" type="string | ((state: TabsRootState) => string | undefined)">
  CSS class applied to the element, or a function that
  returns a class based on the component's state.
</ParamField>

<ParamField body="Root.defaultValue" type="any" default="0">
  The default value. Use when the component is not controlled.
  When the value is `null`, no Tab will be active.
</ParamField>

<ParamField body="Root.onValueChange" type="((value: any, eventDetails: TabsRootChangeEventDetails) => void)">
  Callback invoked when new value is being set.

  The event `reason` is `'none'` for user-initiated changes, such as a click
  or keyboard navigation; `'initial'` for the first automatic selection or
  fallback in uncontrolled roots when `defaultValue` is omitted or
  `undefined`, including when the implicit initial value is disabled or
  missing; `'disabled'` for automatic fallback when the selected tab becomes
  disabled in uncontrolled roots; or `'missing'` for automatic fallback when
  the selected tab is removed, or when an explicit `defaultValue` never
  matches a mounted tab in uncontrolled roots.

  For automatic changes, the selected value can be `null` when no enabled Tab
  is available as a fallback.

  Automatic changes cannot be canceled; calling `eventDetails.cancel()` for
  `'initial'`, `'disabled'`, or `'missing'` has no effect.
</ParamField>

<ParamField body="Root.orientation" type="&#x22;horizontal&#x22; | &#x22;vertical&#x22;" default="horizontal">
  The component orientation (layout flow direction).
</ParamField>

<ParamField body="Root.render" type="ReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, TabsRootState>">
  Allows you to replace the component's HTML element
  with a different tag, or compose it with another component.

  Accepts a `ReactElement` or a function that returns the element to render.
</ParamField>

<ParamField body="Root.style" type="CSSProperties | ((state: TabsRootState) => CSSProperties | undefined)">
  Style applied to the element, or a function that
  returns a style object based on the component's state.
</ParamField>

<ParamField body="Root.value" type="any">
  The value of the currently active `Tab`. Use when the component is controlled.
  When the value is `null`, no Tab will be active.
</ParamField>

### Tabs.List

<ParamField body="List.activateOnFocus" type="boolean" default="false">
  Whether to automatically change the active tab on arrow key focus.
  Otherwise, tabs will be activated using \<kbd>Enter\</kbd> or \<kbd>Space\</kbd> key press.
</ParamField>

<ParamField body="List.className" type="string | ((state: TabsListState) => string | undefined)">
  CSS class applied to the element, or a function that
  returns a class based on the component's state.
</ParamField>

<ParamField body="List.loopFocus" type="boolean" default="true">
  Whether to loop keyboard focus back to the first item
  when the end of the list is reached while using the arrow keys.
</ParamField>

<ParamField body="List.render" type="ReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, TabsListState>">
  Allows you to replace the component's HTML element
  with a different tag, or compose it with another component.

  Accepts a `ReactElement` or a function that returns the element to render.
</ParamField>

<ParamField body="List.style" type="CSSProperties | ((state: TabsListState) => CSSProperties | undefined)">
  Style applied to the element, or a function that
  returns a style object based on the component's state.
</ParamField>

### Tabs.Tab

<ParamField body="Tab.badge" type="ReactNode">
  Content rendered after the label, such as a count.
</ParamField>

<ParamField body="Tab.className" type="string | ((state: TabsTabState) => string | undefined)">
  CSS class applied to the element, or a function that
  returns a class based on the component's state.
</ParamField>

<ParamField body="Tab.disabled" type="boolean">
  Whether the Tab is disabled.

  If a first Tab on a `<Tabs.List>` is disabled, it won't initially be selected.
  Instead, the next enabled Tab will be selected.
  However, it does not work like this during server-side rendering, as it is not known
  during pre-rendering which Tabs are disabled.
  To work around it, ensure that `defaultValue` or `value` on `<Tabs.Root>` is set to an enabled Tab's value.
</ParamField>

<ParamField body="Tab.nativeButton" type="boolean" default="true">
  Whether the component renders a native `<button>` element when replacing it
  via the `render` prop.
  Set to `false` if the rendered element is not a button (for example, `<div>`).
</ParamField>

<ParamField body="Tab.render" type="ReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, TabsTabState>">
  Allows you to replace the component's HTML element
  with a different tag, or compose it with another component.

  Accepts a `ReactElement` or a function that returns the element to render.
</ParamField>

<ParamField body="Tab.size" type="&#x22;sm&#x22; | &#x22;md&#x22;" default="sm">
  Visual size of the tab.
</ParamField>

<ParamField body="Tab.startIcon" type="ReactNode">
  Icon rendered before the label.
</ParamField>

<ParamField body="Tab.style" type="CSSProperties | ((state: TabsTabState) => CSSProperties | undefined)">
  Style applied to the element, or a function that
  returns a style object based on the component's state.
</ParamField>

<ParamField body="Tab.value" type="any" required>
  The value of the Tab.
</ParamField>

### Tabs.Panel

<ParamField body="Panel.className" type="string | ((state: TabsPanelState) => string | undefined)">
  CSS class applied to the element, or a function that
  returns a class based on the component's state.
</ParamField>

<ParamField body="Panel.keepMounted" type="boolean" default="false">
  Whether to keep the HTML element in the DOM while the panel is hidden.
</ParamField>

<ParamField body="Panel.render" type="ReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, TabsPanelState>">
  Allows you to replace the component's HTML element
  with a different tag, or compose it with another component.

  Accepts a `ReactElement` or a function that returns the element to render.
</ParamField>

<ParamField body="Panel.style" type="CSSProperties | ((state: TabsPanelState) => CSSProperties | undefined)">
  Style applied to the element, or a function that
  returns a style object based on the component's state.
</ParamField>

<ParamField body="Panel.value" type="any" required>
  The value of the TabPanel. It will be shown when the Tab with the corresponding value is active.
</ParamField>
