Skip to content

Tabs

Organize content into separate views where only one is visible at a time.

import { Tabs } from 'asterui'

Basic Usage

Simple tabs with content switching handled automatically.

Content of Tab 1
import { Tabs, Typography } from 'asterui'

function App() {
  return (
      <Tabs>
        <Tabs.Panel tab="Tab 1" key="1">
          <Typography.Text>Content of Tab 1</Typography.Text>
        </Tabs.Panel>
        <Tabs.Panel tab="Tab 2" key="2">
          <Typography.Text>Content of Tab 2</Typography.Text>
        </Tabs.Panel>
        <Tabs.Panel tab="Tab 3" key="3">
          <Typography.Text>Content of Tab 3</Typography.Text>
        </Tabs.Panel>
      </Tabs>
    )
}

export default App

Settings Page

Complete settings page with forms using floating label inputs.

import { Tabs, Space, Input, Button } from 'asterui'

function App() {
  return (
      <Tabs defaultActiveKey="account" variant="border">
        <Tabs.Panel tab="Account" key="account">
          <Space direction="vertical" size="md">
            <Input floatingLabel="Username" placeholder="john_doe" />
            <Input floatingLabel="Email" type="email" placeholder="john@example.com" />
            <Button color="primary">Save</Button>
          </Space>
        </Tabs.Panel>
        <Tabs.Panel tab="Security" key="security">
          <Space direction="vertical" size="md">
            <Input floatingLabel="Current Password" type="password" />
            <Input floatingLabel="New Password" type="password" />
            <Button color="primary">Update</Button>
          </Space>
        </Tabs.Panel>
      </Tabs>
    )
}

export default App

Boxed Variant

Tabs with enclosed box styling.

Home content
import { Tabs, Typography } from 'asterui'

function App() {
  return (
      <Tabs variant="box">
        <Tabs.Panel tab="Home" key="home">
          <Typography.Text>Home content</Typography.Text>
        </Tabs.Panel>
        <Tabs.Panel tab="Profile" key="profile">
          <Typography.Text>Profile content</Typography.Text>
        </Tabs.Panel>
        <Tabs.Panel tab="Settings" key="settings">
          <Typography.Text>Settings content</Typography.Text>
        </Tabs.Panel>
      </Tabs>
    )
}

export default App

Lifted Variant

Tabs with 3D lifted appearance.

Overview content
import { Tabs, Typography } from 'asterui'

function App() {
  return (
      <Tabs variant="lift">
        <Tabs.Panel tab="Overview" key="1">
          <Typography.Text>Overview content</Typography.Text>
        </Tabs.Panel>
        <Tabs.Panel tab="Reports" key="2">
          <Typography.Text>Reports content</Typography.Text>
        </Tabs.Panel>
        <Tabs.Panel tab="Analytics" key="3">
          <Typography.Text>Analytics content</Typography.Text>
        </Tabs.Panel>
      </Tabs>
    )
}

export default App

Different Sizes

Tabs in various sizes using Space and Typography components.

Small
Small tabs content
Large
Large tabs content
import { Tabs, Space, Typography } from 'asterui'

function App() {
  return (
      <Space direction="vertical" size="md">
        <div>
          <Typography.Text strong>Small</Typography.Text>
          <Tabs size="sm">
            <Tabs.Panel tab="Tab 1" key="1"><Typography.Text>Small tabs content</Typography.Text></Tabs.Panel>
            <Tabs.Panel tab="Tab 2" key="2"><Typography.Text>Content 2</Typography.Text></Tabs.Panel>
          </Tabs>
        </div>
        <div>
          <Typography.Text strong>Large</Typography.Text>
          <Tabs size="lg">
            <Tabs.Panel tab="Tab 1" key="1"><Typography.Text>Large tabs content</Typography.Text></Tabs.Panel>
            <Tabs.Panel tab="Tab 2" key="2"><Typography.Text>Content 2</Typography.Text></Tabs.Panel>
          </Tabs>
        </div>
      </Space>
    )
}

export default App

Disabled Tab

Disable specific tabs.

Active content
import { Tabs, Typography } from 'asterui'

function App() {
  return (
      <Tabs>
        <Tabs.Panel tab="Active" key="1">
          <Typography.Text>Active content</Typography.Text>
        </Tabs.Panel>
        <Tabs.Panel tab="Disabled" key="2" disabled>
          <Typography.Text>Cannot see this</Typography.Text>
        </Tabs.Panel>
        <Tabs.Panel tab="Also Active" key="3">
          <Typography.Text>Active content</Typography.Text>
        </Tabs.Panel>
      </Tabs>
    )
}

export default App

Data-Driven Pattern

Use items prop for data-driven tabs with icons.

Home content
import { Tabs, notification, Typography } from 'asterui'
import { HomeIcon, UserIcon, Cog6ToothIcon } from '@aster-ui/icons'
import { useState } from 'react'

function App() {
  const [activeKey, setActiveKey] = useState('home')
  
  const items = [
    { key: 'home', label: 'Home', icon: <HomeIcon size="sm" />, children: <Typography.Text>Home content</Typography.Text> },
    { key: 'profile', label: 'Profile', icon: <UserIcon size="sm" />, children: <Typography.Text>Profile content</Typography.Text> },
    { key: 'settings', label: 'Settings', icon: <Cog6ToothIcon size="sm" />, children: <Typography.Text>Settings content</Typography.Text> },
  ]
  
  return (
      <Tabs
        items={items}
        activeKey={activeKey}
        onChange={(key) => {
          setActiveKey(key)
          notification.info({ message: `Switched to ${key}` })
        }}
        variant="border"
      />
    )
}

export default App

Bottom Position

Tabs positioned below the content.

Content appears above the tabs
import { Tabs, Typography } from 'asterui'

function App() {
  return (
      <Tabs position="bottom" variant="border">
        <Tabs.Panel tab="Tab 1" key="1">
          <Typography.Text>Content appears above the tabs</Typography.Text>
        </Tabs.Panel>
        <Tabs.Panel tab="Tab 2" key="2">
          <Typography.Text>Second tab content</Typography.Text>
        </Tabs.Panel>
        <Tabs.Panel tab="Tab 3" key="3">
          <Typography.Text>Third tab content</Typography.Text>
        </Tabs.Panel>
      </Tabs>
    )
}

export default App
PropertyDescriptionTypeDefault
childrenTab panels (compound pattern)React.ReactNode-
itemsTab items (data-driven pattern)TabItem[]-
activeKeyCurrent active tab key (controlled)string-
defaultActiveKeyDefault active tab key (uncontrolled)string-
onChangeCallback when tab changes(key: string) => void-
variantVisual style variant'box' | 'border' | 'lift'-
sizeTab size'xs' | 'sm' | 'md' | 'lg' | 'xl'-
positionTab position relative to content'top' | 'bottom''top'
data-testidTest ID prefix for child elementsstring-
classNameAdditional CSS classesstring-
PropertyDescriptionTypeDefault
keyUnique identifierstring-
labelTab button labelReact.ReactNode-
childrenTab panel contentReact.ReactNode-
disabledDisable the tabbooleanfalse
iconTab iconReact.ReactNode-
PropertyDescriptionTypeDefault
keyUnique identifier for the tab (React key prop)string-
tabTab button labelReact.ReactNode-
disabledDisable the tabbooleanfalse
iconTab iconReact.ReactNode-
childrenTab panel contentReact.ReactNode-
  • Uses proper ARIA roles: tablist, tab, and tabpanel
  • Keyboard navigation: Arrow keys move between tabs, Tab key moves focus into the panel
  • Active tab is indicated with aria-selected="true"
  • Disabled tabs use aria-disabled for proper communication
  • Tab panels use aria-labelledby to associate with their tab
  • Use activeKey for controlled tabs, defaultActiveKey for uncontrolled
  • Use items prop for data-driven tabs, Tabs.Panel for compound pattern
  • Use position="bottom" to place tabs below content