Tabs
Enhance a list of anchor links into a tabs pattern with the <kelp-tabs> web component.
Usage
Wrap a list of anchor links and its associated content in a <kelp-tabs> element. Add the [tabs] attribute to your list of anchor links.
You can use any classes you’d like to achieve the desired layout. This example uses the .list-inline class to display the tabs as an inline list, and a .callout class for the content.
<kelp-tabs>
<ul class="list-inline" tabs>
<li><a href="#wizard">Wizard</a></li>
<li><a href="#sorcerer">Sorcerer</a></li>
<li><a href="#druid">Druid</a></li>
</ul>
<div class="callout outline" id="wizard">
Wizards gain their magic through study...
</div>
<div class="callout outline" id="sorcerer">
Sorcerers get their power from an otherworldly being...
</div>
<div class="callout outline" id="druid">
Druids get their power from nature...
</div>
</kelp-tabs>The <kelp-tabs> component adds all of the ARIA attributes and keyboard and focus behaviors required for an accessible component.
It also removes any anchor links that do not have a matching content element.
Options
Starting Tab
The <kelp-tabs> component displays the first tab and it’s content as the default.
To start with a different tab, add the [start] attribute to the <kelp-tabs> component, and use the ID of the content to show as its value.
<kelp-tabs start="#druid">
<ul tabs>
<li><a href="#wizard">Wizard</a></li>
<li><a href="#sorcerer">Sorcerer</a></li>
<li><a href="#druid">Druid</a></li>
</ul>
<div id="wizard">...</div>
<div id="sorcerer">...</div>
<div id="druid">...</div>
</kelp-tabs>Vertical Tabs
For a side-by-side layout, you can display your tabs vertically instead of horizontally.
Add the [vertical] attribute to the <kelp-tabs> component. This adds an additional required ARIA attribute, and adjusts the keyboard navigation to use the up and down arrow keys in addition to left and right.
Use the .list-unstyled class instead of .list-inline, and optionally use the .stack and .gap-* classes to control spacing.
The demo below uses the .sidecar class to achieve the side-by-side layout, but you can also use the .grid class to more tightly control the design if you’d prefer.
<kelp-tabs vertical>
<div class="sidecar">
<ul class="list-unstyled stack gap-4xs" tabs>
<li><a href="#wizard">Wizard</a></li>
<li><a href="#sorcerer">Sorcerer</a></li>
<li><a href="#druid">Druid</a></li>
</ul>
<div>
<div id="wizard">...</div>
<div id="sorcerer">...</div>
<div id="druid">...</div>
</div>
</div>
</kelp-tabs>Manual Mode
When a tab is in focus, pressing the left and right arrow keys shifts focus and activates the next tab’s content.
If you add the [manual] attribute, focus will shift, but the tab content will not be displayed until the user explicitly activates the button (with a click or the return or spacebar keys).
Generally speaking, the default behavior is better for accessibility. Manual mode is useful when tab content is loaded asynchronously from an API.
<kelp-tabs manual>
<ul class="list-inline" tabs>
<li><a href="#wizard">Wizard</a></li>
<li><a href="#sorcerer">Sorcerer</a></li>
<li><a href="#druid">Druid</a></li>
</ul>
<div id="wizard">...</div>
<div id="sorcerer">...</div>
<div id="druid">...</div>
</kelp-tabs>Tab Colors
You can use .primary, .secondary, .success, .danger, and .warning color classes to adjust the color of the tab buttons.
Add the class to the [tabs] list element. You can use the same color, or different ones if you’d prefer, for the tab content.
<kelp-tabs start="#druid">
<ul class="list-inline secondary" tabs>
<li><a href="#wizard">Wizard</a></li>
<li><a href="#sorcerer">Sorcerer</a></li>
<li><a href="#druid">Druid</a></li>
</ul>
<div class="callout primary" id="wizard">...</div>
<div class="callout danger" id="sorcerer">...</div>
<div class="callout success" id="druid">...</div>
</kelp-tabs>Events
The <kelp-tabs> element emits a few events.
kelp-tabs:readyemits when the component is instantiated.kelp-tabs:select-beforeemits before a tab’s visibility is selected.cancelable- you can stop the select from happening by runningevent.preventDefault().event.detail.currentTab- the currently selected tab element.event.detail.currentPane- the currently selected content pane element.event.detail.nextTab- the tab element that will be selected.event.detail.nextPane- the content pane element that will be selected.
kelp-tabs:selectemits after a tab’s visibility has been selected.event.detail.tab- the tab element that was selected.event.detail.pane- the content pane element that was selected.
document.addEventListener('kelp-tabs:ready', (event) => {
console.log('ready:', event.target);
});
document.addEventListener('kelp-tabs:select-before', (event) => {
console.log('A tab is about to selected in:', event.target);
console.log('The currently selected tab is:', event.detail.currentTab);
console.log('The currently selected content pane is:', event.detail.currentPane);
console.log('The tab that will be selected is:', event.detail.nextTab);
console.log('The content pane that will be selected is:', event.detail.nextPane);
// Stop this change from happening
// The currentTab and currentPane will remain selected
event.preventDefault();
});
document.addEventListener('kelp-tabs:select', (event) => {
console.log('A tab was selected in:', event.target);
console.log('The currently selected tab is:', event.detail.tab);
console.log('The currently selected content pane is:', event.detail.pane);
});
Methods
While web components are self-instantiating, the <kelp-tabs> element has a few methods you can manually run if needed.
.select(tab)- Select a tab and it’s content. Pass in thetabelement to select..init()- Manually initialize the component, if it fails for some reason.
const tabs = document.querySelector('kelp-tabs');
const druidTab = tabs.querySelector('[aria-controls="druid"]');
// Show the druid tab
tabs.select(druidTab);