View this page with live demos!
The tab-list
, tab-item
, and tab-panel
elements together represent content that is presented one panel at a time. They are built with accessibility in mind and implement the WAI-ARIA guidelines for tabs.
- A
tab-list
represents a set of tabs, where only one tab's contents may be presented at a time. - A
tab-item
represents a reference of a single panel of information in a tab list. - A
tab-panel
represents a panel of information.
Apples are usually red, but sometimes they can be green.
Oranges are, well, orange!
Bananas are yellow and usually curved.
<tab-list aria-label="Learn about fruits">
<tab-item for="example-1-tab-1" selected>Apples</tab-item>
<tab-item for="example-1-tab-2">Oranges</tab-item>
<tab-item for="example-1-tab-3">Bananas</tab-item>
</tab-list>
<tab-panel id="example-1-tab-1">
<p>Apples are usually red, but sometimes they can be green.</p>
</tab-panel>
<tab-panel id="example-1-tab-2">
<p>Oranges are, well, orange!</p>
</tab-panel>
<tab-panel id="example-1-tab-3">
<p>Bananas are yellow and usually curved.</p>
</tab-panel>
Installation
You can import through CDN:
<script type="module" src="https://unpkg.com/@auroratide/tab-list/lib/define.js"></script>
Or, you may install through NPM and include it as part of your build process:
$ npm i @auroratide/tab-list
import '@auroratide/tab-list/lib/define.js'
Usage
tab-list
, tab-item
, and tab-panel
are markup elements that you can use in your HTML document. To use them together, it is best to follow these guidelines:
tab-item
elements must be contained within atab-list
. They need not be direct descendents.tab-panel
must define a uniqueid
.tab-item
must define thefor
attribute, whose value is theid
of its correspondingtab-panel
.
<tab-list>
<!-- tab-item must be in a tab-list, and defines `for` to be
the corresponding tab-panel id -->
<tab-item for="tab-panel-id">
</tab-list>
<!-- tab-panel defines an id -->
<tab-panel id="tab-panel-id">
<p>Any content you want</p>
</tab-panel>
The following are good accessibility practices:
tab-list
should be labelled with a name representing the collection of tabs, either witharia-label
oraria-labelledby
.tab-panel
elements can theoretically be anywhere on the page, though it's best if they are the next focusable item after thetab-list
.
Automatic Activation
By default, a tab must be clicked in order for its panel to be revealed. With automatic activation, a tab only needs to acquire focus to show its tab. In general, WAI-ARIA recommends automatic activation for the best accessibility, unless animations induce lag.
You can enable automatic activation by setting the activation
attribute to "automatic"
on the tab list element.
Tomatoes are red. People like to tell you they are fruit and not vegetables.
Carrots are orange, and also a root.
Some squashes are yellow, and they come in all shapes and sizes.
<tab-list activation="automatic" aria-label="Learn about vegetables">
<tab-item for="example-5-tab-1" selected>Tomatoes</tab-item>
<tab-item for="example-5-tab-2">Carrots</tab-item>
<tab-item for="example-5-tab-3">Squashes</tab-item>
</tab-list>
Vertical Tab List
By default, tabs are listed horizontally, and they can be navigated with the left and right arrow keys.
By setting the orientation
attribute to "vertical"
, you can make a vertical tab list. This makes it navigable with the up and down arrow keys instead.
Tomatoes are red. People like to tell you they are fruit and not vegetables.
Carrots are orange, and also a root.
Some squashes are yellow, and they come in all shapes and sizes.
<tab-list orientation="vertical" aria-label="Learn about vegetables">
<tab-item for="example-2-tab-1" selected>Tomatoes</tab-item>
<tab-item for="example-2-tab-2">Carrots</tab-item>
<tab-item for="example-2-tab-3">Squashes</tab-item>
</tab-list>
Setting a selected tab
You can set the selected
attribute on one tab-item
in a tab-list
. This will mark that item as selected and show its panel.
Apples are usually red, but sometimes they can be green.
Oranges are, well, orange!
Bananas are yellow and usually curved.
<tab-item selected for="example-3-tab-3">Bananas</tab-item>
Note: Only one tab-item
can be selected at a time! If you attempt to set multiple as selected, only the first selected tabl's panel will be shown.
All Attributes
For tab-list
:
Attribute | Description |
---|---|
orientation |
Either "horizontal" or "vertical" . Represents whether the tab list should be presented horizontally or vertically, and affects whether they are navigated with the left/right or up/down keys respectively. "horizontal" by default. |
activation |
Either "manual" or "automatic" . Represents whether a click (manual) or focus (automatic) is required to show a tab's panel. "manual" by default. |
For tab-item
:
Attribute | Description |
---|---|
for |
Required. Should be the same as the id of the tab's respective panel. |
selected |
Either present or not. Represents whether this tab's panel should be shown. |
CSS Customization
Since these are native custom elements, they can be styled the same way as regular HTML elements.
Of note:
tab-item[selected]
will style the currently selected tab.tab-list[orientation="vertical"]
can style vertical tab lists.tab-panel[hidden]
styles hidden tabs, in case you want transitions.
Here's an example of a fully customized tab list:
Ingredients for making apple pie:
- 8 Granny Smith apples
- ½ cup butter
- 3 tablespoons flour
- ½ cup white sugar
- ½ cup brown sugar
- ¼ water
- A double-crust pie pastry
Ingredients for making orange sorbet:
- 2 cups orange juice pulp
- 1½ cup almond milk
- 1 tablespoon orange zest
- 1 tablespoon lemon juice
- ¼ teaspoon salt
- 1 teaspoon vanilla extract
- ½ teaspoon sweetener
Ingredients for making banana pudding:
- 14 bananas
- 5 ounce packet instant vanilla pudding
- 2 cups milk
- 14 ounce can condensed milk
- 1 tablespoon vanilla extract
- 12 ounces frozen whipped topping
- 16 ounces vanilla wafers
div.tab-container {
box-shadow: 0 0.125em 0.25em oklch(0% 0 0 / 0.25);
}
tab-list {
background: oklch(55% 0.119 250);
gap: 0;
}
tab-item {
border: none;
border-radius: 0;
background: oklch(55% 0.119 250);
color: oklch(97.5% 0.005 255);
padding: 0.625em 1.125em;
border-right: 0.125em solid oklch(38% 0.125 250);
}
tab-item:hover:not([selected]),
tab-item:focus:not([selected]) {
background: oklch(38% 0.125 250);
}
tab-item[selected] {
background: oklch(22% 0.021 255);
border-color: transparent;
color: oklch(80% 0.005 255);
}
div.tab-panels-container { display: grid; }
tab-panel {
grid-area: 1 / 1;
border: none;
padding: 0.625em 1.125em 1.125em;
opacity: 1;
transition: opacity 0.2s ease-in-out;
}
tab-panel[hidden] {
display: block;
opacity: 0;
}
Events
The tab-list
element dispatches the following events:
Name | When Triggered |
---|---|
tab-list:change |
Whenever the currently selected tab changes |
The tab-list:change
event contains references to the previously selected tab and the newly selected tab:
tabList.addEventListener('tab-list:change', e => {
console.log(e.detail.from)
console.log(e.detail.to)
})
Accessibility
This custom element is built with accessibility in mind! It follows the WAI-ARIA guidelines for tabs (the tablist
, tab
, and tabpanel
roles).
- When focus enters the tab list, the currently active tab item is focused.
- Left and Right can be used to navigate the tabs.
- Enter or Space select the currently focused tab.
- Home goes to the first tab, and End goes to the last tab.
Not (yet) Implemented
The following features are desired of tab lists, but are not yet implemented:
- Auto-opening a panel when its corresponding tab receives focus.
- Native support for removable tabs.
- Tabs that open popup menus.