Beta Preview

Tabs

Tabs organize content into multiple sections and allow users to navigate between them.

orientation 
keyboardActivation 
isDisabled 
Example
Tabs.tsx
Tabs.css
import {Tabs, TabList, Tab, TabPanel} from './Tabs';
import Home from '@react-spectrum/s2/illustrations/gradient/generic2/Home';
import Folder from '@react-spectrum/s2/illustrations/gradient/generic2/FolderOpen';
import Search from '@react-spectrum/s2/illustrations/gradient/generic2/Search';
import Settings from '@react-spectrum/s2/illustrations/gradient/generic1/GearSetting';

<Tabs>
  <TabList aria-label="Tabs">
    <Tab id="home">Home</Tab>
    <Tab id="files">Files</Tab>
    <Tab id="search">Search</Tab>
    <Tab id="settings">Settings</Tab>
  </TabList>
  <TabPanel id="home" style={{display: 'flex', alignItems: 'center', justifyContent: 'center'}}>
    <Home />
  </TabPanel>
  <TabPanel id="files" style={{display: 'flex', alignItems: 'center', justifyContent: 'center'}}>
    <Folder />
  </TabPanel>
  <TabPanel id="search" style={{display: 'flex', alignItems: 'center', justifyContent: 'center'}}>
    <Search />
  </TabPanel>
  <TabPanel id="settings" style={{display: 'flex', alignItems: 'center', justifyContent: 'center'}}>
    <Settings />
  </TabPanel>
</Tabs>

Content

TabList follows the Collection Components API, accepting both static and dynamic collections. This example shows a dynamic collection, passing a list of objects to the items prop, and a function to render the children.

Tab body 1
import {Tabs, TabList, Tab, TabPanel} from './Tabs';
import {Button} from './Button';
import {Collection} from 'react-aria-components';
import {useState} from 'react';

function Example() {
  let [tabs, setTabs] = useState([
    {id: 1, title: 'Tab 1', content: 'Tab body 1'},
    {id: 2, title: 'Tab 2', content: 'Tab body 2'},
    {id: 3, title: 'Tab 3', content: 'Tab body 3'}
  ]);

  let addTab = () => {
    setTabs(tabs => [
      ...tabs,
      {
        id: tabs.length + 1,
        title: `Tab ${tabs.length + 1}`,
        content: `Tab body ${tabs.length + 1}`
      }
    ]);
  };

  let removeTab = () => {
    if (tabs.length > 1) {
      setTabs(tabs => tabs.slice(0, -1));
    }
  };

  return (
    <Tabs style={{width: '100%'}}>
      <div style={{display: 'flex'}}>
        <TabList 
          aria-label="Dynamic tabs"
          items={tabs}
          style={{flex: 1}}>
          {item => <Tab>{item.title}</Tab>}
        </TabList>
        <div className="button-group">
          <Button onPress={addTab}>Add tab</Button>
          <Button onPress={removeTab}>Remove tab</Button>
        </div>
      </div>
      <Collection items={tabs}>
        {item => <TabPanel>{item.content}</TabPanel>}
      </Collection>
    </Tabs>
  );
}

Use the href prop on a <Tab> to create a link. See the client side routing guide to learn how to integrate with your framework. This example uses a simple hash-based router to sync the selected tab to the URL.

import {Tabs, TabList, Tab, TabPanel} from './Tabs';
import {useSyncExternalStore} from 'react';

export default function Example() {
  let hash = useSyncExternalStore(subscribe, getHash, getHashServer);

  return (
    <Tabs selectedKey={hash}>
      <TabList aria-label="Tabs">
        <Tab id="#/" href="#/">Home</Tab>
        <Tab id="#/shared" href="#/shared">Shared</Tab>
        <Tab id="#/deleted" href="#/deleted">Deleted</Tab>
      </TabList>
      <TabPanel id="#/">Home</TabPanel>
      <TabPanel id="#/shared">Shared</TabPanel>
      <TabPanel id="#/deleted">Deleted</TabPanel>
    </Tabs>
  );
}

function getHash() {
  return location.hash.startsWith('#/') ? location.hash : '#/';
}

function getHashServer() {
  return '#/';
}

function subscribe(fn) {
  addEventListener('hashchange', fn);
  return () => removeEventListener('hashchange', fn);
}

Selection

Use the defaultSelectedKey or selectedKey prop to set the selected tab. The selected key corresponds to the id prop of a <Tab>. Tabs can be disabled with the isDisabled prop. See the selection guide for more details.

Selected tab: files

import type {Key} from 'react-aria-components';
import {Tabs, TabList, Tab, TabPanel} from './Tabs';
import Home from '@react-spectrum/s2/illustrations/gradient/generic2/Home';
import Folder from '@react-spectrum/s2/illustrations/gradient/generic2/FolderOpen';
import Search from '@react-spectrum/s2/illustrations/gradient/generic2/Search';
import Settings from '@react-spectrum/s2/illustrations/gradient/generic1/GearSetting';
import {useState} from 'react';

function Example() {
  let [tab, setTab] = useState<Key>("files");

  return (
    <div>
      <Tabs
        selectedKey={tab}
        onSelectionChange={setTab}
      >
        <TabList aria-label="Tabs">
          <Tab id="home">Home</Tab>
          <Tab id="files">Files</Tab>
          <Tab id="search" isDisabled>Search</Tab>
          <Tab id="settings">Settings</Tab>
        </TabList>
        <TabPanel id="home" style={{display: 'flex', alignItems: 'center', justifyContent: 'center'}}>
          <Home />
        </TabPanel>
        <TabPanel id="files" style={{display: 'flex', alignItems: 'center', justifyContent: 'center'}}>
          <Folder />
        </TabPanel>
        <TabPanel id="search" style={{display: 'flex', alignItems: 'center', justifyContent: 'center'}}>
          <Search />
        </TabPanel>
        <TabPanel id="settings" style={{display: 'flex', alignItems: 'center', justifyContent: 'center'}}>
          <Settings />
        </TabPanel>
      </Tabs>
      <p>Selected tab: {tab}</p>
    </div>
  );
}

API

Shows a tabs component with labels for each tab, a selection state, and the tab panel.Section 1Section 2TabTab (selected)Tab listTab panel