The Tabs component provides an accessible tabbed interface with automatic keyboard navigation. It uses the <ot-tabs> web component to manage tab state and panel visibility.
Basic Usage
Wrap tab buttons and panels in <ot-tabs>. Use role="tablist", role="tab", and role="tabpanel".
< ot-tabs >
< div role = "tablist" >
< button role = "tab" > Account </ button >
< button role = "tab" > Password </ button >
< button role = "tab" > Notifications </ button >
</ div >
< div role = "tabpanel" >
< h3 > Account Settings </ h3 >
< p > Manage your account information here. </ p >
</ div >
< div role = "tabpanel" >
< h3 > Password Settings </ h3 >
< p > Change your password here. </ p >
</ div >
< div role = "tabpanel" >
< h3 > Notification Settings </ h3 >
< p > Configure your notification preferences. </ p >
</ div >
</ ot-tabs >
Features
Keyboard Navigation Use Arrow Left/Right to navigate between tabs
ARIA Support Automatic aria-controls, aria-labelledby, and aria-selected management
Auto IDs Generates unique IDs for tabs and panels if not provided
Custom Events Emits ot-tab-change event on tab change
Web Component API
Properties
Get or set the currently active tab index (0-based)
Fired when the active tab changes. Event detail includes:
index - The index of the newly active tab
tab - The tab element that was activated
JavaScript Usage
Setting Active Tab
const tabs = document . querySelector ( 'ot-tabs' );
// Set the second tab as active
tabs . activeIndex = 1 ;
// Get current active index
console . log ( tabs . activeIndex ); // 1
Listening to Tab Changes
const tabs = document . querySelector ( 'ot-tabs' );
tabs . addEventListener ( 'ot-tab-change' , ( e ) => {
console . log ( 'Tab changed to index:' , e . detail . index );
console . log ( 'Tab element:' , e . detail . tab );
});
HTML Structure
Wrap in ot-tabs
The <ot-tabs> element is required as the outer container
Add tablist
A single <div role="tablist"> containing all tab buttons
Add tab buttons
Each <button role="tab"> represents a clickable tab
Add panels
Each <div role="tabpanel"> contains the content for its corresponding tab
Initial Active Tab
To set a specific tab as initially active, add aria-selected="true" to the desired tab button:
< ot-tabs >
< div role = "tablist" >
< button role = "tab" > Tab 1 </ button >
< button role = "tab" aria-selected = "true" > Tab 2 </ button >
< button role = "tab" > Tab 3 </ button >
</ div >
< div role = "tabpanel" > Content 1 </ div >
< div role = "tabpanel" > Content 2 (shown by default) </ div >
< div role = "tabpanel" > Content 3 </ div >
</ ot-tabs >
If no tab has aria-selected="true", the first tab will be active by default.
Accessibility
The Tabs component automatically handles:
ARIA attributes : Sets aria-controls, aria-labelledby, and aria-selected
Keyboard navigation : Arrow keys move between tabs
Focus management : Active tab receives focus on keyboard navigation
Tab indexing : Only the active tab is focusable via Tab key
Ensure each tab has a corresponding panel. The component will log a warning if tabs or panels are missing.
Styling
The component uses CSS custom properties for theming:
[ role = "tablist" ] {
background-color : var ( --muted );
border-radius : var ( --radius-medium );
padding : var ( --space-1 );
gap : var ( --space-1 );
}
[ role = "tab" ] {
padding : var ( --space-2 ) var ( --space-3 );
font-size : var ( --text-7 );
font-weight : var ( --font-medium );
}
[ role = "tab" ][ aria-selected = "true" ] {
background-color : var ( --background );
box-shadow : var ( --shadow-small );
}