ADVERTISEMENT
Google AdSense Slot (headerLeaderboard)
Set your Publisher ID in src/config/ads.ts to display live ads.
How-To: 50+ Real-World Developer Recipes• 6 min read
How To: Accessible Tabbed Interfaces
Build keyboard-navigable, accessible tabbed interfaces following the WAI-ARIA tabs design pattern.
The WAI-ARIA Tabs Design Pattern
Accessible tabbed widgets require specific semantic roles and states so screen reader users understand the component hierarchy:
role="tablist": Wraps the collection of tab buttons.role="tab": Applied to each individual tab button, with aria-selected="true|false" and aria-controls="panel-id".role="tabpanel": Applied to the container displaying the active panel content, with aria-labelledby="tab-id".JavaScript Tab Controller
function setupTabs() {
const tabs = document.querySelectorAll('[role="tab"]');
const panels = document.querySelectorAll('[role="tabpanel"]');
tabs.forEach(tab => {
tab.addEventListener('click', () => {
// 1. Deactivate all tabs
tabs.forEach(t => {
t.setAttribute('aria-selected', 'false');
t.classList.remove('active');
});
// 2. Hide all panels
panels.forEach(p => p.hidden = true);
// 3. Activate clicked tab
tab.setAttribute('aria-selected', 'true');
tab.classList.add('active');
// 4. Reveal controlled panel
const targetPanel = document.getElementById(tab.getAttribute('aria-controls'));
if (targetPanel) targetPanel.hidden = false;
});
});
}ADVERTISEMENT
Google AdSense Slot (inContentBanner)
Set your Publisher ID in src/config/ads.ts to display live ads.
Test Yourself With Exercise
Which ARIA attribute indicates whether a tab button is currently active and selected?