Source: https://app-studio-6167b.web.app/docs/Tabs

@app-studio/components

# Tabs

A versatile component for organizing and displaying content in separate, selectable sections.

[View component source](https://github.com/rize-network/app-studio-components/blob/main/src/components/Tabs/Tabs.tsx)

## Import

```ts
import { Tabs } from '@app-studio/components';
```

New to the library? Complete [installation and provider setup](https://app-studio-6167b.web.app/docs/installation) first.

## Interactive examples

Try the component, then open Code to copy the complete example.

```jsx
import React, { useState } from 'react';
import { View, Text } from 'app-studio';
import { Button } from '@app-studio/components';
import { Tabs } from '@app-studio/components';

export const ControlledTabs = () => {
  const [activeTab, setActiveTab] = useState<string | number>('profile');

  const tabs = [
    {
      title: 'Profile',
      value: 'profile',
      content: (
        <View padding={20}>
          <Text fontWeight="600" marginBottom={12} fontSize={18}>
            Profile Settings
          </Text>
          <Text color="color-gray-600">
            Manage your public profile, bio, and avatar.
          </Text>
        </View>
      ),
    },
    {
      title: 'Account',
      value: 'account',
      content: (
        <View padding={20}>
          <Text fontWeight="600" marginBottom={12} fontSize={18}>
            Account Details
          </Text>
          <Text color="color-gray-600">
            Update your email, password, and security preferences.
          </Text>
        </View>
      ),
    },
    {
      title: 'Notifications',
      value: 'notifications',
      content: (
        <View padding={20}>
          <Text fontWeight="600" marginBottom={12} fontSize={18}>
            Notification Preferences
          </Text>
          <Text color="color-gray-600">
            Configure how and when you want to be notified.
          </Text>
        </View>
      ),
    },
  ];

  return (
    <View width="100%">
      <View
        marginBottom={20}
        padding={16}
        backgroundColor="color-blue-50"
        borderRadius={8}
        border="1px dashed"
        borderColor="color-blue-200"
      >
        <Text marginBottom={12}>
          Current Active Value: <Text fontWeight="bold">{activeTab}</Text>
        </Text>
        <View display="flex" flexDirection="row" gap={10}>
          <Button
            size="sm"
            variant={activeTab === 'profile' ? 'primary' : 'outline'}
            onClick={() => setActiveTab('profile')}
          >
            Select Profile
          </Button>
          <Button
            size="sm"
            variant={activeTab === 'account' ? 'primary' : 'outline'}
            onClick={() => setActiveTab('account')}
          >
            Select Account
          </Button>
          <Button
            size="sm"
            variant={activeTab === 'notifications' ? 'primary' : 'outline'}
            onClick={() => setActiveTab('notifications')}
          >
            Select Notifications
          </Button>
        </View>
      </View>

      <Tabs
        tabs={tabs}
        value={activeTab}
        onTabChange={(tab) => {
          console.log('Tab changed:', tab);
          if (tab.value) setActiveTab(tab.value);
        }}
      />
    </View>
  );
};
```

## Props

Required props are marked below. A dash indicates an unspecified default. Design system configuration can override implementation defaults.

**Tabs**

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `tabs` | `Tab[]` | `—` | Array of tab objects to be displayed. Each tab needs a unique `value`. (Data-driven approach)[Source](https://github.com/rize-network/app-studio-components/blob/main/src/components/Tabs/Tabs/Tabs.props.ts#L11) |
| `defaultValue` | `string \| number` | `—` | Optional value of the tab to be active initially. Defaults to the first tab if not provided or not found.[Source](https://github.com/rize-network/app-studio-components/blob/main/src/components/Tabs/Tabs/Tabs.props.ts#L13) |
| `onTabChange` | `((activeTab: Tab) => void)` | `—` | Optional callback function triggered when the active tab changes. Receives the newly active tab object.[Source](https://github.com/rize-network/app-studio-components/blob/main/src/components/Tabs/Tabs/Tabs.props.ts#L15) |
| `views` | `TabsStyles` | `—` | Optional styles object to customize the appearance of the tabs container, headers, text, and content area.[Source](https://github.com/rize-network/app-studio-components/blob/main/src/components/Tabs/Tabs/Tabs.props.ts#L17) |
| `variant` | `TabsVariant` `"pill"``"underline"``"segmented"` | `—` | Visual presentation style for the tab list.[Source](https://github.com/rize-network/app-studio-components/blob/main/src/components/Tabs/Tabs/Tabs.props.ts#L19) |
| `iconPosition` | `"bottom" \| "left" \| "right" \| "top"` `"bottom"``"left"``"right"``"top"` | `—` | Optional position of the icon relative to the text in tab headers.[Source](https://github.com/rize-network/app-studio-components/blob/main/src/components/Tabs/Tabs/Tabs.props.ts#L21) |
| `renderTab` | `((tab: Tab, isActive: boolean, onClick: () => void) => React.ReactNode)` | `—` | Optional custom renderer for a single tab header. Receives the tab data, whether it's currently active, and an onClick handler to activate the tab.[Source](https://github.com/rize-network/app-studio-components/blob/main/src/components/Tabs/Tabs/Tabs.props.ts#L26) |
| `renderContent` | `((activeTab: Tab) => React.ReactNode)` | `—` | Optional custom renderer for the content area. Receives the currently active tab object. If not provided, the `content` property from the active tab object will be rendered.[Source](https://github.com/rize-network/app-studio-components/blob/main/src/components/Tabs/Tabs/Tabs.props.ts#L36) |
| `keepMounted` | `boolean` | `—` | By default only the ACTIVE tab's content is mounted — inactive tabs do not exist in the DOM (their state resets on switch, and tests must activate a tab before asserting on its content). Set `keepMounted` to mount every tab's content up front and toggle visibility with `display: none`, preserving internal state across switches. Only applies to the data-driven `tabs` path; `renderContent` still receives the active tab only.[Source](https://github.com/rize-network/app-studio-components/blob/main/src/components/Tabs/Tabs/Tabs.props.ts#L47) |
| `value` | `string \| number` | `—` | Current value for controlled compound component pattern[Source](https://github.com/rize-network/app-studio-components/blob/main/src/components/Tabs/Tabs/Tabs.props.ts#L50) |
| `onValueChange` | `((value: string \| number) => void)` | `—` | Callback when tab value changes in compound component pattern. Receives the tab's value — matching `Tabs.type.ts` and `Tabs.state.ts`, which already declared `string \| number` while this one said `any`.[Source](https://github.com/rize-network/app-studio-components/blob/main/src/components/Tabs/Tabs/Tabs.props.ts#L56) |
| `children` | View type `string \| number \| bigint \| boolean \| React.ReactElement<unknown, string \| React.JSXElementConstructor<any>> \| Iterable<React.ReactNode> \| React.ReactPortal \| Promise<string \| number \| bigint \| boolean \| React.ReactPortal \| React.ReactElement<unknown, string \| React.JSXElementConstructor<any>> \| Iterable<React.ReactNode> \| null \| undefined> \| null` | `—` | Children for compound component pattern[Source](https://github.com/rize-network/app-studio-components/blob/main/src/components/Tabs/Tabs/Tabs.props.ts#L58) |

### Tabs.List

**Tabs.List**

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `children` Required | View type `string \| number \| bigint \| boolean \| React.ReactElement<unknown, string \| React.JSXElementConstructor<any>> \| Iterable<React.ReactNode> \| React.ReactPortal \| Promise<string \| number \| bigint \| boolean \| React.ReactPortal \| React.ReactElement<unknown, string \| React.JSXElementConstructor<any>> \| Iterable<React.ReactNode> \| null \| undefined> \| null` | `—` | Children (TabsTrigger components)[Source](https://github.com/rize-network/app-studio-components/blob/main/src/components/Tabs/Tabs/Tabs.props.ts#L93) |
| `views` | `{ container?: ViewProps; }` | `—` | Custom styles for the list container[Source](https://github.com/rize-network/app-studio-components/blob/main/src/components/Tabs/Tabs/Tabs.props.ts#L95) |

### Tabs.Trigger

**Tabs.Trigger**

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `value` Required | `string` | `—` | Unique value for this tab[Source](https://github.com/rize-network/app-studio-components/blob/main/src/components/Tabs/Tabs/Tabs.props.ts#L105) |
| `children` Required | View type `string \| number \| bigint \| boolean \| React.ReactElement<unknown, string \| React.JSXElementConstructor<any>> \| Iterable<React.ReactNode> \| React.ReactPortal \| Promise<string \| number \| bigint \| boolean \| React.ReactPortal \| React.ReactElement<unknown, string \| React.JSXElementConstructor<any>> \| Iterable<React.ReactNode> \| null \| undefined> \| null` | `—` | Children content for the trigger[Source](https://github.com/rize-network/app-studio-components/blob/main/src/components/Tabs/Tabs/Tabs.props.ts#L107) |
| `disabled` | `boolean` | `—` | Whether this trigger is disabled[Source](https://github.com/rize-network/app-studio-components/blob/main/src/components/Tabs/Tabs/Tabs.props.ts#L109) |
| `views` | `{ trigger?: ViewProps; activeState?: ViewProps; }` | `—` | Custom styles for the trigger[Source](https://github.com/rize-network/app-studio-components/blob/main/src/components/Tabs/Tabs/Tabs.props.ts#L111) |

### Tabs.Content

**Tabs.Content**

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `value` Required | `string` | `—` | Value that this content corresponds to[Source](https://github.com/rize-network/app-studio-components/blob/main/src/components/Tabs/Tabs/Tabs.props.ts#L122) |
| `children` Required | View type `string \| number \| bigint \| boolean \| React.ReactElement<unknown, string \| React.JSXElementConstructor<any>> \| Iterable<React.ReactNode> \| React.ReactPortal \| Promise<string \| number \| bigint \| boolean \| React.ReactPortal \| React.ReactElement<unknown, string \| React.JSXElementConstructor<any>> \| Iterable<React.ReactNode> \| null \| undefined> \| null` | `—` | Children content to display when this tab is active[Source](https://github.com/rize-network/app-studio-components/blob/main/src/components/Tabs/Tabs/Tabs.props.ts#L124) |
| `views` | `{ content?: ViewProps; }` | `—` | Custom styles for the content[Source](https://github.com/rize-network/app-studio-components/blob/main/src/components/Tabs/Tabs/Tabs.props.ts#L126) |

For shared layout, color, and responsive properties, read [Styling & composition](https://app-studio-6167b.web.app/docs/styling) and [Responsive layouts](https://app-studio-6167b.web.app/docs/responsive). Additional native element attributes depend on the target platform.

## Usage guidance

- Give controls a visible label or an accessible name, and verify keyboard interaction. See [Accessibility](https://app-studio-6167b.web.app/docs/accessibility).
- For controlled inputs, update the value from the callback shown in the props table. Keep application state in your component or form library.
- These previews run in the browser. Check [React Native setup](https://app-studio-6167b.web.app/docs/react-native) for platform requirements and differences.
