Tabs

Tabs

The Tabs component organizes related content into separate views that can be switched between without leaving the current page.

import Tab from "rocksolidjs/Tab";
import TabsContext from "rocksolidjs/TabsContext";
import TabPanel from "rocksolidjs/TabPanel";
import Tabs from "rocksolidjs/Tabs";

export default function Example() {
  return (
    <div class="max-w-5xl w-full">
      <TabsContext defaultValue="home" tabId="basic">
        <Tabs class="mb-2">
          <Tab label="Home" value="home" />
          <Tab label="Profile" value="profile" />
          <Tab label="Settings" value="settings" />
        </Tabs>
        <TabPanel value="home" tabIndex={0}>
          Welcome to the home page.
        </TabPanel>
        <TabPanel value="profile" tabIndex={0}>
          View and manage your profile.
        </TabPanel>
        <TabPanel value="settings" tabIndex={0}>
          Manage your account settings.
        </TabPanel>
      </TabsContext>
    </div>
  );
}

Usage

Wrap the Tabs and TabPanel components in a TabsContext. Each Tab must have a unique value, and its corresponding TabPanel must use the same value.

<TabsContext defaultValue="home">
  <Tabs>
    <Tab label="Home" value="home" />
    <Tab label="Profile" value="profile" />
    <Tab label="Settings" value="settings" />
  </Tabs>

  <TabPanel value="home">
    Home content
  </TabPanel>
  <TabPanel value="profile">
    Profile content
  </TabPanel>
  <TabPanel value="settings">
    Settings content
  </TabPanel>
</TabsContext>

When a tab is selected, the TabPanel with the matching value is displayed.

Examples

Controlled

Use the value prop on TabsContext to control the active tab. Use onChange to respond when the user selects a different tab.

import { createSignal } from "solid-js";
import Tab from "rocksolidjs/Tab";
import TabsContext from "rocksolidjs/TabsContext";
import TabPanel from "rocksolidjs/TabPanel";
import Tabs from "rocksolidjs/Tabs";

export default function Example() {
  const [activeTab, setActiveTab] = createSignal("home");

  return (
    <div class="max-w-5xl w-full">
      <TabsContext
        value={activeTab()}
        onChange={(_event, tab) => setActiveTab(tab)}
        tabId="controlled"
      >
        <Tabs class="mb-2">
          <Tab label="Home" value="home" />
          <Tab label="Profile" value="profile" />
          <Tab label="Settings" value="settings" />
        </Tabs>
        <TabPanel value="home">
          Welcome to the home page.
        </TabPanel>
        <TabPanel value="profile">
          View and manage your profile.
        </TabPanel>
        <TabPanel value="settings">
          Manage your account settings.
        </TabPanel>
      </TabsContext>
    </div>
  );
}

Default Value

Use defaultValue to specify the tab that should be active initially without controlling the active tab.

import Tab from "rocksolidjs/Tab";
import TabsContext from "rocksolidjs/TabsContext";
import TabPanel from "rocksolidjs/TabPanel";
import Tabs from "rocksolidjs/Tabs";

export default function Example() {
  return (
    <div class="max-w-5xl w-full">
      <TabsContext defaultValue="profile" tabId="default-value">
        <Tabs class="mb-2">
          <Tab label="Home" value="home" />
          <Tab label="Profile" value="profile" />
          <Tab label="Settings" value="settings" />
        </Tabs>
        <TabPanel value="home">
          Welcome to the home page.
        </TabPanel>
        <TabPanel value="profile">
          This tab is selected by default.
        </TabPanel>
        <TabPanel value="settings">
          Manage your account settings.
        </TabPanel>
      </TabsContext>
    </div>
  );
}

Orientation

Use the orientation prop to arrange tabs horizontally or vertically.

import Tab from "rocksolidjs/Tab";
import TabsContext from "rocksolidjs/TabsContext";
import TabPanel from "rocksolidjs/TabPanel";
import Tabs from "rocksolidjs/Tabs";

export default function Example() {
  return (
    <div class="max-w-5xl w-full grid grid-cols-[100px_1fr] gap-4">
      <TabsContext defaultValue="home" tabId="orientation">
        <Tabs orientation="vertical">
          <Tab label="Home" value="home" />
          <Tab label="Profile" value="profile" />
          <Tab label="Settings" value="settings" />
        </Tabs>
        <div>
          <TabPanel value="home">
            Welcome to the home page.
          </TabPanel>
          <TabPanel value="profile">
            View and manage your profile.
          </TabPanel>
          <TabPanel value="settings">
            Manage your account settings.
          </TabPanel>
        </div>
      </TabsContext>
    </div>
  );
}

Centered

Use the centered prop to center the tabs within the available space.

import Tab from "rocksolidjs/Tab";
import TabsContext from "rocksolidjs/TabsContext";
import TabPanel from "rocksolidjs/TabPanel";
import Tabs from "rocksolidjs/Tabs";

export default function Example() {
  return (
    <div class="max-w-5xl w-full">
      <TabsContext defaultValue="home" tabId="centered">
        <Tabs centered class="mb-3">
          <Tab label="Home" value="home" />
          <Tab label="Profile" value="profile" />
          <Tab label="Settings" value="settings" />
        </Tabs>
        <TabPanel value="home">
          Welcome to the home page.
        </TabPanel>
        <TabPanel value="profile">
          View and manage your profile.
        </TabPanel>
        <TabPanel value="settings">
          Manage your account settings.
        </TabPanel>
      </TabsContext>
    </div>
  );
}

Icons

Use the icon prop to display an icon alongside a tab label.

import Tab from "rocksolidjs/Tab";
import TabsContext from "rocksolidjs/TabsContext";
import TabPanel from "rocksolidjs/TabPanel";
import Tabs from "rocksolidjs/Tabs";

export default function Example() {
  return (
    <div class="max-w-5xl w-full">
      <TabsContext defaultValue="home" tabId="icons">
        <Tabs class="mb-2">
          <Tab
            icon={<HomeIcon />}
            iconPosition="top"
            label="Home"
            value="home"
          />
          <Tab
            icon={<ProfileIcon />}
            iconPosition="start"
            label="Profile"
            value="profile"
          />
          <Tab
            icon={<SettingsIcon />}
            iconPosition="end"
            label="Settings"
            value="settings"
          />
        </Tabs>

        <TabPanel value="home">
          Welcome to the home page.
        </TabPanel>
        <TabPanel value="profile">
          View and manage your profile.
        </TabPanel>
        <TabPanel value="settings">
          Manage your account settings.
        </TabPanel>
      </TabsContext>
    </div>
  );
}

function HomeIcon() {
  return (
    <svg
      width="20"
      height="20"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      stroke-width="2"
      stroke-linecap="round"
      stroke-linejoin="round"
      aria-hidden={true}
    >
      <path d="m3 10 9-7 9 7" />
      <path d="M5 9v11h14V9" />
      <path d="M9 20v-6h6v6" />
    </svg>
  );
}

function ProfileIcon() {
  return (
    <svg
      width="20"
      height="20"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      stroke-width="2"
      stroke-linecap="round"
      stroke-linejoin="round"
      aria-hidden={true}
    >
      <circle cx="12" cy="8" r="4" />
      <path d="M4 21a8 8 0 0 1 16 0" />
    </svg>
  );
}

function SettingsIcon() {
  return (
    <svg
      width="20"
      height="20"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      stroke-width="2"
      stroke-linecap="round"
      stroke-linejoin="round"
      aria-hidden={true}
    >
      <path d="M12 15.5a3.5 3.5 0 1 0 0-7 3.5 3.5 0 0 0 0 7Z" />
      <path d="M19.4 15a1.7 1.7 0 0 0 .3 1.9l.1.1-1.7 1.7-.1-.1a1.7 1.7 0 0 0-1.9-.3 1.7 1.7 0 0 0-1 1.6v.1h-2.4v-.1a1.7 1.7 0 0 0-1-1.6 1.7 1.7 0 0 0-1.9.3l-.1.1L8 17l.1-.1a1.7 1.7 0 0 0 .3-1.9 1.7 1.7 0 0 0-1.6-1H6.7v-2.4h.1a1.7 1.7 0 0 0 1.6-1 1.7 1.7 0 0 0-.3-1.9L8 8.6l1.7-1.7.1.1a1.7 1.7 0 0 0 1.9.3 1.7 1.7 0 0 0 1-1.6v-.1h2.4v.1a1.7 1.7 0 0 0 1 1.6 1.7 1.7 0 0 0 1.9-.3l.1-.1 1.7 1.7-.1.1a1.7 1.7 0 0 0-.3 1.9 1.7 1.7 0 0 0 1.6 1h.1V14h-.1a1.7 1.7 0 0 0-1.6 1Z" />
    </svg>
  );
}

Icon Position

Use the iconPosition prop to control where an icon appears relative to the tab label.

import Tab from "rocksolidjs/Tab";
import TabsContext from "rocksolidjs/TabsContext";
import TabPanel from "rocksolidjs/TabPanel";
import Tabs from "rocksolidjs/Tabs";

export default function Example() {
  return (
    <div class="max-w-5xl w-full">
      <TabsContext defaultValue="top" tabId="icon-position">
        <Tabs class="mb-2">
          <Tab
            icon={<Icon />}
            iconPosition="top"
            label="Top"
            value="top"
          />
          <Tab
            icon={<Icon />}
            iconPosition="bottom"
            label="Bottom"
            value="bottom"
          />
          <Tab
            icon={<Icon />}
            iconPosition="start"
            label="Start"
            value="start"
          />
          <Tab
            icon={<Icon />}
            iconPosition="end"
            label="End"
            value="end"
          />
        </Tabs>

        <TabPanel value="top">
          Icon positioned above the label.
        </TabPanel>
        <TabPanel value="bottom">
          Icon positioned below the label.
        </TabPanel>
        <TabPanel value="start">
          Icon positioned to the start of the label.
        </TabPanel>
        <TabPanel value="end">
          Icon positioned to the end of the label.
        </TabPanel>
      </TabsContext>
    </div>
  );
}

function Icon() {
  return (
    <span aria-hidden="true">●</span>
  );
}

Disabled

Use the disabled prop to prevent users from selecting a tab.

import Tab from "rocksolidjs/Tab";
import TabsContext from "rocksolidjs/TabsContext";
import TabPanel from "rocksolidjs/TabPanel";
import Tabs from "rocksolidjs/Tabs";

export default function Example() {
  return (
    <div class="max-w-5xl w-full">
      <TabsContext defaultValue="home" tabId="disabled-example">
        <Tabs class="mb-2">
          <Tab label="Home" value="home" />
          <Tab label="Profile" value="profile" />
          <Tab label="Settings" value="settings" disabled />
        </Tabs>
        <TabPanel value="home" tabIndex={0}>
          Welcome to the home page.
        </TabPanel>
        <TabPanel value="profile" tabIndex={0}>
          View and manage your profile.
        </TabPanel>
        <TabPanel value="settings" tabIndex={0}>
          Manage your account settings.
        </TabPanel>
      </TabsContext>
    </div>
  );
}

Tab ID

Use the tabId prop to automatically associate each tab with its corresponding tab panel.

import Tab from "rocksolidjs/Tab";
import TabsContext from "rocksolidjs/TabsContext";
import TabPanel from "rocksolidjs/TabPanel";
import Tabs from "rocksolidjs/Tabs";

export default function Example() {
  return (
    <div class="max-w-5xl w-full">
      <TabsContext defaultValue="home" tabId="basic">
        <Tabs class="mb-2">
          <Tab label="Home" value="home" />
          <Tab label="Profile" value="profile" />
          <Tab label="Settings" value="settings" />
        </Tabs>
        <TabPanel value="home" tabIndex={0}>
          Welcome to the home page.
        </TabPanel>
        <TabPanel value="profile" tabIndex={0}>
          View and manage your profile.
        </TabPanel>
        <TabPanel value="settings" tabIndex={0}>
          Manage your account settings.
        </TabPanel>
      </TabsContext>
    </div>
  );
}

The tabId prop generates the accessibility attributes needed to link each role="tab" with its corresponding role="tabpanel", including id, aria-controls, and aria-labelledby.

Provide a unique tabId for each TabsContext instance when using multiple tab groups on the same page.

If you do not provide tabId, you can set these accessibility attributes manually. Give each tab and tab panel a unique id, then use aria-controls on the tab and aria-labelledby on the corresponding tab panel.

<Tab
  label="Home"
  value="home"
  id="home-tab"
  aria-controls="home-panel"
/>

<TabPanel
  value="home"
  tabIndex={0}
  id="home-panel"
  aria-labelledby="home-tab"
>
  Welcome to the home page.
</TabPanel>

Custom Styling

Use the class prop to customize the appearance of TabsContext, Tabs, Tab, and TabPanel components. Use slotProps on Tab when you need to customize individual tab slots.

import Tab from "rocksolidjs/Tab";
import TabsContext from "rocksolidjs/TabsContext";
import TabPanel from "rocksolidjs/TabPanel";
import Tabs from "rocksolidjs/Tabs";
import { createSignal } from "solid-js";

export default function Example() {
  const [activeTab, setActiveTab] = createSignal("home");

  const getClass = (tab: string) => (`
    shadow-none 
    ${activeTab() === tab ? `
      text-white
      bg-blue-500 dark:bg-blue-500
      hover:bg-blue-600 hover:dark:bg-blue-400
      active:bg-blue-600/80 active:dark:bg-blue-400/80
    ` : ""}
  `);

  return (
    <div class="w-full">
      <TabsContext
        value={activeTab()}
        onChange={(_event, tab) => setActiveTab(tab)}
        tabId="custom-styled"
      >
        <Tabs 
          class="border-none grid grid-cols-3 bg-neutral-100 dark:bg-neutral-800"
        >
          <Tab
            class={getClass("home")}
            label="Home"
            value="home"
          />
          <Tab
            class={getClass("profile")}
            label="Profile"
            value="profile"
          />
          <Tab
            class={getClass("settings")}
            label="Settings"
            value="settings"
          />
        </Tabs>

        <TabPanel class="p-4" value="home">
          Welcome to the home page.
        </TabPanel>
        <TabPanel class="p-4" value="profile">
          View and manage your profile.
        </TabPanel>
        <TabPanel class="p-4" value="settings">
          Manage your account settings.
        </TabPanel>
      </TabsContext>
    </div>
  );
}

Accessibility

  • Associate each Tab with its corresponding TabPanel so assistive technologies can understand the relationship between the tab and its content.
  • Ensure every Tab has a corresponding TabPanel with a matching value.
  • Keep tab labels concise and meaningful.
  • Use the orientation prop to reflect the visual arrangement of the tabs.
  • Use the disabled prop when a tab is temporarily unavailable, rather than relying only on visual styling to communicate its state.
  • Do not rely on icons alone to communicate the purpose of a tab when a text label can provide clearer context.
  • Ensure tab and panel content remains accessible when switching between tabs.

API

TabsContext

TabsContext manages the active tab and provides the selected value to its child Tabs and TabPanel components.

Prop Type Required Default Description
children JSXElement No The Tabs and TabPanel components rendered within the context.
defaultValue string No Sets the initially active tab when the component is uncontrolled.
onChange (event: Event, activeTab: string) => void No Called when the active tab changes. Receives the event and the newly active tab value.
value string No Controls the currently active tab. When provided, the active tab is controlled by the parent.
tabId string No A unique identifier used to associate tabs with their corresponding tab panels through accessibility attributes such as id, aria-controls, and aria-labelledby.

Tabs

Tabs renders the tab navigation and supports horizontal or vertical layouts, centered positioning, and custom styling.

Prop Type Required Default Description
centered boolean No false Centers the tabs within the available space.
class string No Adds custom CSS classes to the tabs container.
orientation "horizontal" | "vertical" No "horizontal" Controls the direction in which the tabs are displayed.

Tab

Tab represents an individual selectable tab. Use value to associate the tab with a TabPanel. Tabs can optionally display a label and icon.

Prop Type Required Default Description
class string No Adds custom CSS classes to the tab.
icon JSXElement No Displays an icon within the tab.
iconPosition "top" | "bottom" | "start" | "end" No "top" Controls the position of the icon relative to the tab label.
label string No The text displayed as the tab label.
value string Yes Identifies the tab and associates it with a TabPanel that has the same value.
slotProps { icon?: object } No Provides additional props for customizing individual tab slots.
  • icon — Props for the icon slot.

TabPanel

TabPanel contains the content associated with a specific tab. Its value must match the value of the corresponding Tab.

Prop Type Required Default Description
class string No Adds custom CSS classes to the tab panel.
value string Yes Identifies the panel and associates it with a Tab that has the same value.
children JSXElement No The content to display inside the tab panel.
  • Accordion — Use Accordion to show and hide related sections vertically.
  • Button — Use Button for standalone actions or navigation.