> ## 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.

# TabButton

> Present route links and actions alongside tabs with consistent styling.

export const StoryEmbed = ({storyId, title, height = 120}) => <>
    <Tabs>
      <Tab title="Light">
        <iframe title={`${title} (light)`} src={`https://storybook.twenty.com/iframe.html?id=${storyId}&viewMode=story&globals=colorScheme:light`} width="100%" height={height} loading="lazy" allow="clipboard-write" style={{
  border: 0
}} />
      </Tab>
      <Tab title="Dark">
        <iframe title={`${title} (dark)`} src={`https://storybook.twenty.com/iframe.html?id=${storyId}&viewMode=story&globals=colorScheme:dark`} width="100%" height={height} loading="lazy" allow="clipboard-write" style={{
  border: 0
}} />
      </Tab>
    </Tabs>
    <a href={`https://storybook.twenty.com/?path=/story/${storyId}`}>
      Open in Storybook
    </a>
  </>;

Use `TabButton` for route links and actions such as adding a tab or opening an overflow menu. It shares the appearance of [Tabs](/ui/primitives/navigation/tabs) and uses [Button](/ui/primitives/input/button) for interaction.

<StoryEmbed storyId="ui-components-tabbutton--display" title="TabButton example" height={120} />

## Usage

```tsx theme={null}
import { TabButton } from 'twenty-ui/components/navigation';
import { IconSettings } from 'twenty-ui/icon';

export const GeneralAction = ({ onOpen }: { onOpen: () => void }) => (
  <TabButton startIcon={<IconSettings />} onClick={onOpen}>
    General
  </TabButton>
);
```

## State and semantics

Your application supplies `active` from its current route or menu state. This prop highlights the control. Set `aria-current="page"` on the current route link. Route links and adjacent actions retain their link or button semantics, with no tab role, `aria-selected`, or panel relationship.

Use `Tabs.Root`, `Tabs.List`, `Tabs.Tab`, `Tabs.Panel`, and optional `Tabs.Indicator` to switch between related content panels. Keep route and action controls outside `Tabs.List`.

## Navigation

Set `href` to render a native link. The current route owns its `active` appearance and `aria-current` value.

```tsx theme={null}
import { TabButton } from 'twenty-ui/components/navigation';
import { IconCreditCard } from 'twenty-ui/icon';

export const BillingLink = () => (
  <TabButton
    href="/billing"
    active
    aria-current="page"
    startIcon={<IconCreditCard />}
  >
    Billing
  </TabButton>
);
```

For client-side routing, supply your router link through `render`, set `nativeButton={false}` and `role="link"`, and pass the resolved destination as `href`. Keep route state and history options on the router link. Custom wrappers must forward the supplied props and ref to their anchor.

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

export const ComposedBillingLink = () => (
  <TabButton
    nativeButton={false}
    role="link"
    href="/billing"
    render={<a />}
    aria-current="page"
    active
  >
    Billing
  </TabButton>
);
```

An explicit `nativeButton` controls the interaction contract even when `href` is present. Match it to the actual rendered element. Disabled links retain their link role and block activation.

## Actions

Without `href`, the control renders a native button with `type="button"`. Native attributes, refs, styles, class names, and event handlers pass through. `render` accepts an element or a function receiving the Button props and state. Refs point to the actual rendered button or anchor, including refs supplied on a composed element.

```tsx theme={null}
import { useState } from 'react';
import { TabButton } from 'twenty-ui/components/navigation';
import { IconPlus } from 'twenty-ui/icon';
import { Text } from 'twenty-ui/primitives/typography';

export const AddTabAction = () => {
  const [count, setCount] = useState(1);

  return (
    <>
      <TabButton startIcon={<IconPlus />} onClick={() => setCount(count + 1)}>
        New Tab
      </TabButton>
      <Text role="status">Tabs: {count}</Text>
    </>
  );
};
```

Use `startIcon`, `endIcon`, and `badge` for supporting content. An avatar passed to an icon slot is decorative when the text names the destination. `size` retains the public Button size contract. An explicit size takes priority over a surrounding `ButtonGroup` size; otherwise the component defaults to `sm`.

## Props

<ParamField body="active" type="boolean" default="false">
  Highlights the current destination or an action associated with the active tab. Does not change the control role.
</ParamField>

<ParamField body="badge" type="ReactNode">
  Content following the label and trailing icon, such as a count.
</ParamField>

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

<ParamField body="endIcon" type="ReactNode">
  Decorative content displayed after the label.
</ParamField>

<ParamField body="focusableWhenDisabled" type="boolean" default="false">
  Whether the button should be focusable when disabled.
</ParamField>

<ParamField body="href" type="string">
  Destination URL. Renders a native anchor when `render` is omitted unless `nativeButton` is explicitly true. Custom renderers retain their own element contract.
</ParamField>

<ParamField body="nativeButton" type="boolean" default="true">
  Whether the rendered root is a native button. Defaults to true for custom renderers. The built-in `href` anchor defaults to false; an explicit value takes precedence.
</ParamField>

<ParamField body="render" type="ReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, ButtonState>">
  Caller-supplied root element or renderer. Native attributes, handlers, event details, and refs reach the rendered root. Use `nativeButton={false}` and `role="link"` for a custom navigation anchor. Router integration belongs to the caller.
</ParamField>

<ParamField body="role" type="AriaRole">
  Role of the root element. Use `link` for custom navigation renderers.
</ParamField>

<ParamField body="size" type="&#x22;md&#x22; | &#x22;sm&#x22;" default="sm">
  Padding of the tab content: sm or md. Explicit size takes precedence over the ButtonGroup size, then sm applies.
</ParamField>

<ParamField body="startIcon" type="ReactNode">
  Decorative content displayed before the label.
</ParamField>

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


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.