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 Tab
s 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 |