comps

Tabs

Composable tab list and panels with arrow-key navigation and ARIA roles wired up.


Tabs is a small set of composable parts — Tabs, TabList, Tab, TabPanel — rather than a monolithic component. That lets you drop a search bar between the list and the panels, or render panels somewhere else entirely.

Try it live

import { useState } from "react";
import { Tabs, TabList, Tab, TabPanel } from "@plyxui/comps";
import { Box, Text } from "@plyxui/primitives";

export default function App() {
const [tab, setTab] = useState("overview");
return (
  <Box padding="lg" style={{ minHeight: "100vh" }}>
    <Tabs value={tab} onChange={setTab}>
      <TabList>
        <Tab value="overview">Overview</Tab>
        <Tab value="usage">Usage</Tab>
        <Tab value="props">Props</Tab>
      </TabList>
      <TabPanel value="overview">
        <Text size="sm">Use the arrow keys to move focus across tabs.</Text>
      </TabPanel>
      <TabPanel value="usage">
        <Text size="sm">Composable parts — drop anything between TabList and TabPanel.</Text>
      </TabPanel>
      <TabPanel value="props">
        <Text size="sm">value + onChange are the only required props on Tabs.</Text>
      </TabPanel>
    </Tabs>
  </Box>
);
}

API

import { Tabs, TabList, Tab, TabPanel } from "@plyxui/comps";

const [tab, setTab] = useState("overview");

<Tabs value={tab} onChange={setTab}>
  <TabList>
    <Tab value="overview">Overview</Tab>
    <Tab value="usage">Usage</Tab>
    <Tab value="props">Props</Tab>
  </TabList>

  <TabPanel value="overview">…</TabPanel>
  <TabPanel value="usage">…</TabPanel>
  <TabPanel value="props">…</TabPanel>
</Tabs>

Accessibility

  • TabList has role="tablist".
  • Each Tab has role="tab", paired with its panel via aria-controls / aria-labelledby.
  • Left and Right arrows move focus between tabs and activate the focused tab.
  • The active tab is tabIndex=0; inactive tabs are -1 so Tab/Shift+Tab steps in and out as a single stop.

Props

Tabs

PropTypeDefault
valuestringrequired
onChange(next: string) => voidrequired
childrenReactNoderequired

TabList

PropTypeDefault
variant"line" | "pill""line"
fillbooleanfalse

TabPanel

keepMounted keeps the panel rendered (hidden via display: none) when inactive. Useful for forms where you don't want to lose input state on tab switch.