Svelte Headless UI

Tabs

Basic example

Tabs are built using the TabGroup, TabList, Tab, TabPanels, and TabPanel components.

By default the first tab is selected, and clicking on any tab or selecting it with the keyboard will activate the corresponding panel.

<script>
  import {
    Tab,
    TabGroup,
    TabList,
    TabPanel,
    TabPanels,
  } from "@rgossiaux/svelte-headlessui";
</script>

<TabGroup>
  <TabList>
    <Tab>Tab 1</Tab>
    <Tab>Tab 2</Tab>
    <Tab>Tab 3</Tab>
  </TabList>
  <TabPanels>
    <TabPanel>Content 1</TabPanel>
    <TabPanel>Content 2</TabPanel>
    <TabPanel>Content 3</TabPanel>
  </TabPanels>
</TabGroup>

Styling

See here for some general notes on styling the components in this library.

The selected tab

To style the active Tab, you can use the selected slot prop that it provides, which tells you whether or not that tab is currently selected. You can also access selected as an argument to a function passed to class (see here). You can use this state to conditionally apply whatever styles you wish.

<script>
  import {
    Tab,
    TabGroup,
    TabList,
    TabPanel,
    TabPanels,
  } from "@rgossiaux/svelte-headlessui";
</script>

<TabGroup>
  <TabList>
    <Tab class={({selected}) => selected ? "tab-selected" : "tab-unselected"}>Tab 1</Tab>
    <!-- ... -->
  </TabList>
  <TabPanels>
    <TabPanel>Content 1</TabPanel>
    <!-- ... -->
  </TabPanels>
</TabGroup>

<style>
  /* WARNING: This is just for demonstration.
      Using :global() in this way can be risky. */
  :global(.tab-selected) {
    background-color: rgb(59 130 246);
    color: rgb(255 255 255);
  }

  :global(.tab-unselected) {
    background-color: rgb(255 255 255);
    color: rgb(0 0 0);
  }
</style>

Disabling a tab

To disable a tab, use the disabled prop on the Tab component. Disabled tabs cannot be selected with the mouse, and are also skipped when navigating the tab list using the keyboard.

<script>
  import {
    Tab,
    TabGroup,
    TabList,
    TabPanel,
    TabPanels,
  } from "@rgossiaux/svelte-headlessui";
</script>

<TabGroup>
  <TabList>
    <Tab>Tab 1</Tab>
    <Tab disabled>Tab 2</Tab>
    <Tab>Tab 3</Tab>
  </TabList>
  <TabPanels>
    <TabPanel>Content 1</TabPanel>
    <TabPanel>Content 2</TabPanel>
    <TabPanel>Content 3</TabPanel>
  </TabPanels>
</TabGroup>

Manually activating tabs

By default, tabs are automatically selected as the user navigates through them using the arrow keys.

If you’d rather not change the current tab until the user presses Enter or Space, use the manual prop on the TabGroup component. This can be helpful if selecting a tab performs an expensive operation and you don’t want to run it unnecessarily.

<script>
  import {
    Tab,
    TabGroup,
    TabList,
    TabPanel,
    TabPanels,
  } from "@rgossiaux/svelte-headlessui";
</script>

<TabGroup manual>
  <TabList>
    <Tab>Tab 1</Tab>
    <Tab>Tab 2</Tab>
    <Tab>Tab 3</Tab>
  </TabList>
  <TabPanels>
    <TabPanel>Content 1</TabPanel>
    <TabPanel>Content 2</TabPanel>
    <TabPanel>Content 3</TabPanel>
  </TabPanels>
</TabGroup>

The manual prop has no impact on mouse interactions; tabs will still be selected as soon as they are clicked.

Vertical tabs

If you’ve styled your TabList to appear vertically, use the vertical prop to enable navigating with the up and down arrow keys instead of with the left and right arrows, and to update the aria-orientation attribute for assistive technologies.

<script>
  import {
    Tab,
    TabGroup,
    TabList,
    TabPanel,
    TabPanels,
  } from "@rgossiaux/svelte-headlessui";
</script>

<TabGroup vertical>
  <TabList>
    <Tab>Tab 1</Tab>
    <Tab>Tab 2</Tab>
    <Tab>Tab 3</Tab>
  </TabList>
  <TabPanels>
    <TabPanel>Content 1</TabPanel>
    <TabPanel>Content 2</TabPanel>
    <TabPanel>Content 3</TabPanel>
  </TabPanels>
</TabGroup>

Specifying the default tab

To change which tab is selected by default, use the defaultIndex={number} prop on the TabGroup component.

<script>
  import {
    Tab,
    TabGroup,
    TabList,
    TabPanel,
    TabPanels,
  } from "@rgossiaux/svelte-headlessui";
</script>

<!-- Note that defaultIndex is 0-based -->
<TabGroup defaultIndex={1}>
  <TabList>
    <Tab>Tab 1</Tab>

    <!-- Selects this tab by default -->
    <Tab>Tab 2</Tab>

    <Tab>Tab 3</Tab>
  </TabList>
  <TabPanels>
    <TabPanel>Content 1</TabPanel>

    <!-- Displays this panel by default -->
    <TabPanel>Content 2</TabPanel>

    <TabPanel>Content 3</TabPanel>
  </TabPanels>
</TabGroup>

If you happen to provide an index that is out of bounds, then the last non-disabled tab will be selected on initial render. For example, <TabGroup defaultIndex={5}> in the above example would select Tab 3.

Listening for changes

To run a function whenever the selected tab changes, use the change event on the TabGroup component.

<script>
  import {
    Tab,
    TabGroup,
    TabList,
    TabPanel,
    TabPanels,
  } from "@rgossiaux/svelte-headlessui";
</script>

<TabGroup on:change={(e) => console.log("Changed selected tab to:", e.detail)}>
  <TabList>
    <Tab>Tab 1</Tab>
    <Tab>Tab 2</Tab>
    <Tab>Tab 3</Tab>
  </TabList>
  <TabPanels>
    <TabPanel>Content 1</TabPanel>
    <TabPanel>Content 2</TabPanel>
    <TabPanel>Content 3</TabPanel>
  </TabPanels>
</TabGroup>

Accessibility notes

Mouse interaction

Clicking a Tab will select that tab and display the corresponding TabPanel.

Keyboard interaction

All interactions apply when a Tab component is focused.

Command Description
<ArrowLeft> / <ArrowRight> Selects the previous/next non-disabled tab
<ArrowUp> / <ArrowDown> when vertical is set Selects the previous/next non-disabled tab
<Home> / <PageUp> Selects the first non-disabled tab
<End> / <PageEnd> Selects the last non-disabled tab
<Enter> / <Space> when manual is set Activates the selected tab

Other

All relevant ARIA attributes are automatically managed.

For a full reference on all accessibility features implemented in Tab, see the ARIA spec on Tabs.

Component API

TabGroup

The main tab group component.

Prop Default Type Description
as div string The element the TabGroup should render as
defaultIndex 0 number The index of the default selected tab
vertical false boolean Whether the orientation of the TabList is vertical instead of horizontal
manual false boolean Whether, in keyboard navigation, the Enter or Space key is necessary to change tabs. By default, the arrow keys will change tabs automatically without hitting Enter/Space. This has no impact on mouse behavior
Slot prop Type Description
selectedIndex number The currently selected index

This component also dispatches a custom event, which is listened to using the Svelte on: directive:

Event name Type of event .detail Description
change number Emitted whenever the active tab changes

TabList

The container for Tab components. The order of the Tab components it contains must correspond to the order of the TabPanels.

Prop Default Type Description
as div string The element the TabList should render as
Slot prop Type Description
selectedIndex number The currently selected index

Tab

This component wraps the selector for an individual tab. All Tabs will be rendered at once.

Prop Default Type Description
as button string The element the Tab should render as
disabled false boolean Whether the Tab is currently disabled
Slot prop Type Description
selected boolean Whether the Tab is currently selected

TabPanels

The container for TabPanel components. The order of the TabPanel components it contains must correspond to the order of the TabList.

Prop Default Type Description
as div string The element the TabPanels should render as
Slot prop Type Description
selectedIndex number The currently selected index

TabPanel

This component wraps the contents of an individual tab. Only one TabPanel will be visible at once.

Prop Default Type Description
as div string The element the TabPanel should render as
Slot prop Type Description
selected boolean Whether or not the TabPanel is currently selected