aria-selected and Tab Patterns
Implement keyboard-accessible tab interfaces.
aria-selected and Tab Patterns is a free HTML Academy lesson on CoddyKit. This is lesson 2 of 4. Any 3 lessons of this learning path are free to read in full — after that, CoddyKit PRO unlocks every lesson, plus hands-on practice with a built-in code editor and a 24/7 AI tutor. It is part of the HTML Academy learning path, and your progress syncs across the web and the CoddyKit app. The HTML Academy course includes 4 lessons in total.
Tab Pattern Overview
A tab interface has three ARIA components:
role="tablist"— container for all tabsrole="tab"— individual tab buttonrole="tabpanel"— the content panel for each tab
ARIA Tab Structure
Complete accessible tab markup:
<div role="tablist" aria-label="Account Settings">
<button role="tab" id="tab-1" aria-selected="true"
aria-controls="panel-1">Profile</button>
<button role="tab" id="tab-2" aria-selected="false"
aria-controls="panel-2" tabindex="-1">Security</button>
<button role="tab" id="tab-3" aria-selected="false"
aria-controls="panel-3" tabindex="-1">Notifications</button>
</div>
<div id="panel-1" role="tabpanel" aria-labelledby="tab-1">
Profile content...
</div>
<div id="panel-2" role="tabpanel" aria-labelledby="tab-2" hidden>
Security content...
</div>aria-selected
aria-selected indicates the currently active item in a selection context:
<!-- In a tablist: -->
<button role="tab" aria-selected="true">Active Tab</button>
<button role="tab" aria-selected="false">Other Tab</button>
<!-- In a listbox: -->
<ul role="listbox">
<li role="option" aria-selected="false">Option 1</li>
<li role="option" aria-selected="true">Option 2</li>
</ul>Tab Keyboard Pattern
ARIA patterns define specific keyboard behavior for tabs:
- Tab — moves focus into the tablist to the selected tab
- Arrow keys — cycle between tabs
- Tab again — moves focus out of tablist into active panel
- Home — first tab
- End — last tab
Tab Keyboard Implementation
Keyboard navigation for tabs using arrow keys:
const tabs = document.querySelectorAll('[role="tab"]');
tabs.forEach((tab, i) => {
tab.addEventListener('keydown', (e) => {
let target;
if (e.key === 'ArrowRight') target = tabs[(i + 1) % tabs.length];
if (e.key === 'ArrowLeft') target = tabs[(i - 1 + tabs.length) % tabs.length];
if (e.key === 'Home') target = tabs[0];
if (e.key === 'End') target = tabs[tabs.length - 1];
if (target) {
activateTab(target);
target.focus();
}
});
});activateTab Function
Function to switch tabs and update ARIA:
function activateTab(selectedTab) {
// Deactivate all tabs:
document.querySelectorAll('[role="tab"]').forEach(tab => {
tab.setAttribute('aria-selected', 'false');
tab.setAttribute('tabindex', '-1');
document.getElementById(tab.getAttribute('aria-controls')).hidden = true;
});
// Activate selected tab:
selectedTab.setAttribute('aria-selected', 'true');
selectedTab.setAttribute('tabindex', '0');
document.getElementById(selectedTab.getAttribute('aria-controls')).hidden = false;
}Roving tabindex Pattern
Tab groups use roving tabindex to keep one tab in the tab order:
<!-- Only the selected tab has tabindex=0 -->
<button role="tab" aria-selected="true" tabindex="0">Active</button>
<button role="tab" aria-selected="false" tabindex="-1">Other</button>
<button role="tab" aria-selected="false" tabindex="-1">Another</button>
<!-- When user arrows to a new tab:
1. Set new tab tabindex=0
2. Set old tab tabindex=-1
3. Focus new tab -->aria-selected vs aria-checked
aria-selected vs aria-checked — different contexts:
aria-selected— used in selection widgets: tabs, options in listbox, items in treearia-checked— used in checkable items: checkboxes, menu items with checkmark
Tabpanel Focus
When a tab is activated, the panel becomes visible but focus stays on the tab:
// Users can then Tab to move into the panel content
// The panel should not automatically receive focus
// Exception: if the panel is very long, consider moving focus
// to the panel heading for long-form content tabs
// Panel should have tabindex=-1 for programmatic focus:
<div id="panel-1" role="tabpanel" aria-labelledby="tab-1" tabindex="-1">Automatic vs Manual Activation
Two tab activation models:
- Automatic — tabs activate as the user arrows through them (simpler UX)
- Manual — user must press Enter/Space to activate after arrowing (better when tab content requires loading)
Accessible Tab Styling
CSS for accessible tab selected state:
[role="tab"] {
border-bottom: 3px solid transparent;
padding: 0.75rem 1rem;
cursor: pointer;
}
[role="tab"][aria-selected="true"] {
border-bottom-color: #0070f3;
font-weight: bold;
}
/* :focus-visible for keyboard users: */
[role="tab"]:focus-visible {
outline: 2px solid #0070f3;
outline-offset: -2px;
}Quick Check
How should keyboard navigation work within a tab list?
Recap: aria-selected and Tabs
Tab pattern essentials:
- tablist → tab (aria-selected) → tabpanel (aria-labelledby)
- Arrow keys navigate between tabs; Tab enters the panel
- Roving tabindex: only active tab has tabindex=0
- aria-selected="true" on the active tab
- Inactive panels use hidden attribute
Learn HTML with an AI tutor — free
Write and run real code in your browser, get instant help from a 24/7 AI tutor, and pick up where you left off on the web or in the app.
- Courses
- 40
- Lessons
- 159
Frequently Asked Questions
Is the “aria-selected and Tab Patterns” lesson free?
Yes — any 3 lessons of the HTML Academy learning path, including “aria-selected and Tab Patterns”, are free to read in full here on the web. After that, CoddyKit PRO unlocks every lesson, plus interactive practice with a built-in code editor and a 24/7 AI tutor. The HTML Academy course includes 4 lessons in total.
What will I learn in “aria-selected and Tab Patterns”?
Implement keyboard-accessible tab interfaces. You practise HTML Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start HTML Academy?
No prior experience is required. HTML Academy on CoddyKit is structured for beginners through advanced learners, so you can start here or from the beginning and move at your own pace. This is lesson 2 of 4.
How long does the “aria-selected and Tab Patterns” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this HTML Academy lesson?
Yes. Every HTML Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- aria-expanded aria-controls for Toggles
- aria-selected and Tab Patterns
- Live Regions aria-live aria-atomic aria-relevant
- Testing with Screen Readers