# Tabs
> Tabs limit visible content by separating it into multiple panels. Only one panel is visible at a time, while all corresponding tabs are always visible — to switch from one panel to another, the corresponding tab has to be selected.

## Import

```js
import { Tabs } from '@gemini-suite/vera-react';

// you may also access Tabs context via hook:
// import { useTabsContext } from '@gemini-suite/vera-react';
```

Tabs is a compound component that consists of multiple parts :

- `Tabs.Root`: The wrapper that contains all other parts and provides context for them.
- `Tabs.List`: The wrapper that holds tabs triggers (buttons).
- `Tabs.Trigger`: The button that opens its associated panel with content and indicates active tab.
- `Tabs.TriggerLabel`: The wrapper for trigger's textual label. It renders a visibly hidden "copy" of the trigger text in bold, reserving box space for when trigger text becomes bold on selected.
- `Tabs.Content`: The wrapper that contains the content associated with a trigger.

## Examples

### Basic

Usually initial state of `Tabs` is having one trigger active and showing matching content.
When you do not need to control the state of the tabs, use `defaultValue` attribute that should match one of the trigger's `value` prop.

```jsx
<Tabs.Root
  defaultValue="insights"
  onValueChange={val => console.log(`Tab changed to ${val}`)}
>
  <Tabs.List marginBottom="spacingS">
    <Tabs.Trigger value="schedule">{'Schedule'}</Tabs.Trigger>
    <Tabs.Trigger value="insights">{'Insights'}</Tabs.Trigger>
    <Tabs.Trigger value="dashboard">{'Dashboard'}</Tabs.Trigger>
    <Tabs.Trigger value="reports">{'Reports'}</Tabs.Trigger>
  </Tabs.List>
  <Tabs.Content value="schedule" padding="spacingS">
    <Heading as="h3">{'Schedule'}</Heading>
    <FakeText words="50,60" />
  </Tabs.Content>
  <Tabs.Content value="insights" padding="spacingS">
    <Heading as="h3">{'Insights'}</Heading>
    <Flex flow="column" gap="spacingS">
      <FakeText words="30,40" />
      <FakeText words="50,60" />
      <FakeText words="20,30" />
    </Flex>
  </Tabs.Content>
  <Tabs.Content value="dashboard" padding="spacingS">
    <Heading as="h3" marginBottom="spacingS">
      {'Dashboard'}
    </Heading>
    <Grid rows="3" columns="none" flow="column" autoColumns="fr">
      <GridItem rowSpan="2">
        <ExampleBox css={{ height: '100%' }} />
      </GridItem>
      <GridItem>
        <ExampleBox />
      </GridItem>
      <GridItem colSpan="2">
        <ExampleBox />
      </GridItem>
      <GridItem colSpan="2">
        <ExampleBox />
      </GridItem>
      <GridItem colSpan="2">
        <ExampleBox />
      </GridItem>
    </Grid>
  </Tabs.Content>
  <Tabs.Content value="reports" padding="spacingS">
    <Heading as="h3">{'Reports'}</Heading>
    <FakeText words="80,90" />
  </Tabs.Content>
</Tabs.Root>
```

### Controlled Tabs

You can easily make the tabs controlled, by passing your own state to `value` prop. `onValueChange` handler is called when
the value changes, allowing you to sync state.

```jsx
() => {
  const [currentTab, setCurrentTab] = React.useState('tab2');

  return (
    <Flex flow="column" cross="start">
      <Tabs.Root value={currentTab} onValueChange={setCurrentTab}>
        <Tabs.List marginBottom="spacingS" withDivider={false}>
          <Tabs.Trigger value="tab1">{'First'}</Tabs.Trigger>
          <Tabs.Trigger value="tab2">{'Second'}</Tabs.Trigger>
          <Tabs.Trigger value="tab3">{'Third'}</Tabs.Trigger>
        </Tabs.List>
        <Tabs.Content value="tab1" padding="spacingS">
          {"I'm first tab."}
          <FakeText words="30,50" />
        </Tabs.Content>
        <Tabs.Content value="tab2" padding="spacingS">
          {"I'm second tab."}
          <FakeText words="50,70" />
        </Tabs.Content>
        <Tabs.Content value="tab3" padding="spacingS">
          {"I'm third tab."}
          <FakeText words="70,90" />
        </Tabs.Content>
      </Tabs.Root>
      <Button onClick={() => setCurrentTab('tab3')}>
        {'Jump to third tab'}
      </Button>
    </Flex>
  );
};
```

### Disabled Tabs

A `Tabs.Trigger` component can take a `isDisabled` prop. When a Tab is disabled, it is skipped during keyboard navigation and it is not clickable. The corresponding `Tabs.Content` component's content will be permanently hidden.

```jsx
<Tabs.Root
  defaultValue="available"
  onValueChange={val => console.log(`Tab changed to ${val}`)}
>
  <Tabs.List marginBottom="spacingS">
    <Tabs.Trigger value="available">{'Available'}</Tabs.Trigger>
    <Tabs.Trigger value="disabled" isDisabled>
      {'Disabled'}
    </Tabs.Trigger>
    <Tabs.Trigger value="accessible">{'Accessible'}</Tabs.Trigger>
    <Tabs.Trigger value="out_of_order" isDisabled>
      {'Out of order'}
    </Tabs.Trigger>
  </Tabs.List>
  <Tabs.Content value="available" padding="spacingS">
    <Heading as="h3">{'Available'}</Heading>
    <FakeText words="20,25" />
  </Tabs.Content>
  <Tabs.Content value="accessible" padding="spacingS">
    <Heading as="h3">{'Accessible'}</Heading>
    <FakeText words="30,40" />
  </Tabs.Content>
  <Tabs.Content value="disabled" padding="spacingS">
    <Heading as="h3">{'Disabled'}</Heading>
    {"Content's not ready."}
  </Tabs.Content>
  <Tabs.Content value="out_of_order" padding="spacingS">
    <Heading as="h3">{'Inoperable'}</Heading>
    {"Content's not ready."}
  </Tabs.Content>
</Tabs.Root>
```

### Tabs with manual activation

By default, `Tabs` are activated automatically. This means when you use the arrow keys to change tabs, the tab is activated and focused.

The other approach is manual tab activation, which means focus is moved without activating the tabs. With focus on a specific tab, users can activate it by pressing <Kbd>Space</Kbd> or <Kbd>Enter</Kbd>.

```jsx
<Tabs.Root defaultValue="tab1" activationMode="manual">
  <Flex flow="column">
    <Tabs.List withDivider={false}>
      <Tabs.Trigger value="tab1">{'First'}</Tabs.Trigger>
      <Tabs.Trigger value="tab2">{'Second'}</Tabs.Trigger>
    </Tabs.List>
    <Tabs.Content value="tab1">{"I'm first tab."}</Tabs.Content>
    <Tabs.Content value="tab2">{"I'm second tab."}</Tabs.Content>
  </Flex>
</Tabs.Root>
```

### Complex triggers

`Tabs.Trigger` can accommodate various content. You can render any element within the trigger such as an icon or a label.

<Callout variant="tip">

Use `Tabs.TriggerLabel` to wrap text content of
`Tabs.Trigger` when trigger contains more than simple
text.

`Tabs.TriggerLabel` renders a visibly hidden
"copy" of the label in bold, reserving box space for when label becomes bold
on selected.

</Callout>

```jsx
<Tabs.Root defaultValue="notifications">
  <Tabs.List marginBottom="spacingS">
    <Tabs.Trigger value="favorites">
      <Flex gap="spacingS">
        <SvgIcon iconName="heart" />
        <Tabs.TriggerLabel>{'Favorites'}</Tabs.TriggerLabel>
      </Flex>
    </Tabs.Trigger>
    <Tabs.Trigger value="settings">
      <Flex gap="spacingS">
        <SvgIcon iconName="settings" />
        <Tabs.TriggerLabel>{'Settings'}</Tabs.TriggerLabel>
      </Flex>
    </Tabs.Trigger>
    <Tabs.Trigger value="notifications">
      <Flex gap="spacingS">
        <SvgIcon iconName="bell" />
        <Tabs.TriggerLabel>{'Notifications'}</Tabs.TriggerLabel>
        <Label circular size="small">
          {'10'}
        </Label>
      </Flex>
    </Tabs.Trigger>
  </Tabs.List>
  <Tabs.Content value="favorites" padding="spacingS">
    <Heading as="h3">{'Favorites'}</Heading>
    <FakeText words="50,60" />
  </Tabs.Content>
  <Tabs.Content value="notifications" padding="spacingS">
    <Heading as="h3">{'Notifications'}</Heading>
    <FakeText words="5,10" />
    <FakeText words="5,10" />
  </Tabs.Content>
  <Tabs.Content value="settings" padding="spacingS">
    <Heading as="h3">{'Settings'}</Heading>
    <FakeText words="80,90" />
  </Tabs.Content>
</Tabs.Root>
```

### Sizes

`Tabs` comes in two size variants: `medium` and `small`. By default, it uses `medium` size, but you can switch it to the `small` size to decrease the size of the triggers.

```jsx
<Flex flow="column">
  <Tabs.Root defaultValue="tab1" size="medium">
    <Flex flow="column">
      <Tabs.List>
        <Tabs.Trigger value="tab1">{'The first tab'}</Tabs.Trigger>
        <Tabs.Trigger value="tab2">{'The second tab'}</Tabs.Trigger>
        <Tabs.Trigger value="tab3">{'The third tab'}</Tabs.Trigger>
      </Tabs.List>
      <Tabs.Content value="tab1">{"I'm first tab panel."}</Tabs.Content>
      <Tabs.Content value="tab2">{"I'm second tab panel."}</Tabs.Content>
      <Tabs.Content value="tab3">{"I'm third tab panel."}</Tabs.Content>
    </Flex>
  </Tabs.Root>
  <Tabs.Root defaultValue="tab1" size="small">
    <Flex flow="column" gap="spacingS">
      <Tabs.List>
        <Tabs.Trigger value="tab1">{'The first tab'}</Tabs.Trigger>
        <Tabs.Trigger value="tab2">{'The second tab'}</Tabs.Trigger>
        <Tabs.Trigger value="tab3">{'The third tab'}</Tabs.Trigger>
      </Tabs.List>
      <Tabs.Content value="tab1">
        <Text variant="zeta">{"I'm first tab panel."}</Text>
      </Tabs.Content>
      <Tabs.Content value="tab2">
        <Text variant="zeta">{"I'm second tab panel."}</Text>
      </Tabs.Content>
      <Tabs.Content value="tab3">
        <Text variant="zeta">{"I'm third tab panel."}</Text>
      </Tabs.Content>
    </Flex>
  </Tabs.Root>
</Flex>
```

---

## Accessibility features

<ul>
  <li iconName="check">

`Tabs` provide deep keyboard interactions.

  </li>
  <li iconName="check">

`Tabs` components follow the [WAI-ARIA Tabs
design pattern](https://www.w3.org/WAI/ARIA/apg/patterns/tabpanel/), semantically linking tabs and their associated tab panels.

  </li>
</ul>

### Keyboard support

<ul>
  <li iconName="minus">

<Kbd>tab</Kbd> when focus moves into the tab list, places focus on the active
tab element. When a trigger is focused, moves focus to the active content.

  </li>
  <li iconName="minus">

<Kbd>←</Kbd> moves focus to the previous tab.

  </li>
  <li iconName="minus">

<Kbd>→</Kbd> moves focus to the next tab.

  </li>
  <li iconName="minus">

<Kbd>home</Kbd> moves focus to the first tab.

  </li>
  <li iconName="minus">

<Kbd>end</Kbd> moves focus to the last tab.

  </li>
  <li iconName="minus">

<Kbd>Space</Kbd> or <Kbd>Enter</Kbd> activates the tab if it was not activated
automatically on focus.

  </li>
</ul>

---

## API Reference

### Tabs.Root

| Name             | Type                      | Default       | Description                                                                                                                                      | Required |
| ---------------- | ------------------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | -------- |
| `defaultValue`   | `string`                  |               | The value of tab that is active when component is first rendered. Use when you do not need to control the state of the tabs.                     |          |
| `value`          | `string`                  |               | The controlled value of the tab to activate. Use in conjunction with `onValueChange`.                                                            |          |
| `onValueChange`  | `(value: string) => void` |               | Event handler called when the value changes.                                                                                                     |          |
| `activationMode` | `"automatic" \| "manual"` | `"automatic"` | When `automatic`, focusing `Tabs.Trigger` results in immediate content change. When `manual` additional key needs to be pressed (Space or Enter) |          |
| `size`           | `"small" \| "medium"`     | `medium`      | The size of the tabs.                                                                                                                            |          |

### Tabs.List

| Name          | Type          | Default | Description                                                                                                                                                                                                                                   | Required |
| ------------- | ------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `css`         | `StitchesCss` |         | Apply styles directly to a component in a similar way how you would define inline styles. Vera uses [Stitches](https://stitches.dev/) under the hood with a fully-typed API and support for features like tokens, media queries, or variants. |          |
| `loop`        | `boolean`     | `true`  | When `true` keyboard navigation will loop from last tab to first, and vice versa.                                                                                                                                                             |          |
| `withDivider` | `boolean`     | `true`  | When `true`, bottom border is visible.                                                                                                                                                                                                        |          |

### Tabs.Trigger

| Name         | Type                                                      | Default  | Description                                                                                                                                                                                                                                                                                  | Required |
| ------------ | --------------------------------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `as`         | `keyof JSX.IntrinsicElements \| React.ComponentType<any>` | `button` | Change the component to a different HTML tag or custom component. This will merge the original component props with the props of the supplied element/component and change the underlying DOM node.   For more details, read our [Composition](/get-started/composition#polymorphism) guide. |          |
| `css`        | `StitchesCss`                                             |          | Apply styles directly to a component in a similar way how you would define inline styles. Vera uses [Stitches](https://stitches.dev/) under the hood with a fully-typed API and support for features like tokens, media queries, or variants.                                                |          |
| `value`      | `string`                                                  |          | Value of tab's trigger-content pair. Has to match one of `Tabs.Content` value to connect matching tab content.                                                                                                                                                                               | Yes      |
| `isDisabled` | `boolean`                                                 | `false`  | When `true`, the trigger will be disabled and skipped during keyboard navigation.                                                                                                                                                                                                            |          |

### Tabs.TriggerLabel

| Name  | Type                                                      | Default | Description                                                                                                                                                                                                                                                                                  | Required |
| ----- | --------------------------------------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `as`  | `keyof JSX.IntrinsicElements \| React.ComponentType<any>` | `span`  | Change the component to a different HTML tag or custom component. This will merge the original component props with the props of the supplied element/component and change the underlying DOM node.   For more details, read our [Composition](/get-started/composition#polymorphism) guide. |          |
| `css` | `StitchesCss`                                             |         | Apply styles directly to a component in a similar way how you would define inline styles. Vera uses [Stitches](https://stitches.dev/) under the hood with a fully-typed API and support for features like tokens, media queries, or variants.                                                |          |

### Tabs.Content

| Name    | Type                                                      | Default | Description                                                                                                                                                                                                                                                                                  | Required |
| ------- | --------------------------------------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `as`    | `keyof JSX.IntrinsicElements \| React.ComponentType<any>` | `div`   | Change the component to a different HTML tag or custom component. This will merge the original component props with the props of the supplied element/component and change the underlying DOM node.   For more details, read our [Composition](/get-started/composition#polymorphism) guide. |          |
| `css`   | `StitchesCss`                                             |         | Apply styles directly to a component in a similar way how you would define inline styles. Vera uses [Stitches](https://stitches.dev/) under the hood with a fully-typed API and support for features like tokens, media queries, or variants.                                                |          |
| `value` | `string`                                                  |         | Value of tab's trigger-content pair. Has to match one of `Tabs.Trigger` value to connect matching tab trigger.                                                                                                                                                                               | Yes      |
