Build an Accessible Tabs Component with HTML, CSS & Vanilla JavaScript Tutorial and Coding Challenge
• Updated 6/18/2026 • accessible tabs componenthtml css javascriptvanilla javascriptfrontend challengeweb accessibilitytutorialcoding challengepractice
Challenge Goal
Build a fully accessible tabs component using semantic HTML, modern CSS, and vanilla JavaScript. Your tabs should support mouse clicks, keyboard navigation, screen readers, and dynamic content switching.
What You Will Build
You will create a reusable tabs interface similar to what is commonly used in dashboards, settings pages, documentation sites, and admin panels.
- Multiple clickable tabs
- Active tab highlighting
- Dynamic tab panel switching
- Keyboard accessibility support
- ARIA attributes for screen readers
Why Accessibility Matters
Accessible UI components improve usability for everyone, including keyboard-only users and people using assistive technologies like screen readers.
This challenge teaches important front-end development concepts used in real-world production applications.
Requirements
- Use semantic HTML structure.
- Add proper ARIA roles and attributes.
- Only one tab panel should be visible at a time.
- Support keyboard navigation using Arrow Left and Arrow Right keys.
- Allow users to activate tabs using Enter or Space.
- Keep the code clean and beginner-friendly.
Input and Output
Input
User interaction through mouse clicks or keyboard navigation.
Output
The correct tab panel becomes visible while inactive panels are hidden.
Starter HTML Structure
<div class="tabs">
<div role="tablist" aria-label="Programming Languages">
<button role="tab" aria-selected="true" aria-controls="panel-html" id="tab-html">
HTML
</button>
<button role="tab" aria-selected="false" aria-controls="panel-css" id="tab-css">
CSS
</button>
<button role="tab" aria-selected="false" aria-controls="panel-js" id="tab-js">
JavaScript
</button>
</div>
<section id="panel-html" role="tabpanel" aria-labelledby="tab-html">
Learn the structure of web pages.
</section>
<section id="panel-css" role="tabpanel" aria-labelledby="tab-css" hidden>
Style modern responsive interfaces.
</section>
<section id="panel-js" role="tabpanel" aria-labelledby="tab-js" hidden>
Add interactivity to applications.
</section>
</div>
Starter CSS
.tabs {
max-width: 600px;
margin: 40px auto;
font-family: Arial, sans-serif;
}
[role="tablist"] {
display: flex;
gap: 10px;
margin-bottom: 20px;
}
[role="tab"] {
padding: 10px 16px;
border: 1px solid #ccc;
background: #f5f5f5;
cursor: pointer;
}
[role="tab"][aria-selected="true"] {
background: #222;
color: #fff;
}
[role="tabpanel"] {
padding: 20px;
border: 1px solid #ddd;
}
Coding Challenge
Write the JavaScript logic that:
- Switches tabs when clicked
- Updates
aria-selectedvalues - Shows the correct tab panel
- Hides inactive panels
- Adds keyboard navigation support
Hints
- Use
querySelectorAll()to select tabs. - Store tabs in an array for keyboard navigation.
- Use the
hiddenattribute to hide inactive panels. - Update accessibility attributes whenever the active tab changes.
Starter JavaScript
const tabs = document.querySelectorAll('[role="tab"]');
function activateTab(tab) {
// Your code here
}
tabs.forEach(tab => {
tab.addEventListener('click', () => {
activateTab(tab);
});
});
Solution Walkthrough
- Select all tabs and tab panels.
- Remove active states from every tab.
- Hide all panels before showing the selected one.
- Update
aria-selectedfor accessibility. - Add keyboard support for Arrow keys and Enter.
Final Solution
const tabs = document.querySelectorAll('[role="tab"]');
const panels = document.querySelectorAll('[role="tabpanel"]');
function activateTab(tab) {
tabs.forEach(item => {
item.setAttribute('aria-selected', 'false');
item.setAttribute('tabindex', '-1');
});
panels.forEach(panel => {
panel.hidden = true;
});
tab.setAttribute('aria-selected', 'true');
tab.removeAttribute('tabindex');
const panelId = tab.getAttribute('aria-controls');
const activePanel = document.getElementById(panelId);
activePanel.hidden = false;
tab.focus();
}
tabs.forEach((tab, index) => {
tab.addEventListener('click', () => {
activateTab(tab);
});
tab.addEventListener('keydown', event => {
let newIndex = index;
if (event.key === 'ArrowRight') {
newIndex = (index + 1) % tabs.length;
}
if (event.key === 'ArrowLeft') {
newIndex = (index - 1 + tabs.length) % tabs.length;
}
if (newIndex !== index) {
activateTab(tabs[newIndex]);
}
if (event.key === 'Enter' || event.key === ' ') {
activateTab(tab);
}
});
});
Common Beginner Mistakes
- Forgetting to hide inactive panels
- Not updating
aria-selected - Ignoring keyboard accessibility
- Using non-semantic HTML elements
Stretch Goals
- Add animated tab transitions.
- Support vertical tabs.
- Remember the active tab using localStorage.
- Convert the component into a reusable JavaScript class.
- Build the same component in React or Vue.
What You Will Learn
- Accessible front-end component design
- ARIA roles and attributes
- DOM manipulation with JavaScript
- Keyboard event handling
- Reusable UI component architecture

