Confused? Create JS Tabs in 3 Simple Steps for 2025
Feeling lost in UI clutter? Learn to create clean, modern, and accessible JavaScript tabs in just 3 simple steps. Our 2025 guide has everything you need.
Elena Petrova
A senior frontend developer passionate about creating accessible and user-friendly web interfaces.
Ever landed on a webpage and felt like you were trying to drink from a firehose? Walls of text, scattered images, buttons everywhere... It’s a common problem in web design: how do we present a lot of information without overwhelming the user? It’s a challenge that can make or break the user experience.
Enter the humble tabbed interface. It’s a design pattern as old as the web itself, but for a good reason: it works. Tabs allow you to neatly organize content into logical chunks, letting users choose what they want to see. It's the digital equivalent of a well-organized filing cabinet, and in 2025, a clean, focused user experience is more important than ever. By grouping related content, you reduce clutter and improve comprehension.
But if you're just starting out, building them from scratch can feel a bit confusing. How do you link the buttons to the content panels? How do you handle the active states and styling? And how do you make them accessible to all users? Don't worry. We're going to break it down into three simple, modern steps. By the end of this guide, you'll be able to create sleek, functional, and accessible tabs with confidence.
Why Use Tabs in Modern Web Design?
Tabs are more than just a space-saver. When used correctly, they offer significant UX benefits:
- Content Organization: They group related information, making it easier for users to navigate complex subjects. Think product details, user settings, or project dashboards.
- Reduced Cognitive Load: By hiding content until it's requested, you present a cleaner, less intimidating interface. Users can focus on one piece of information at a time.
- Improved Page Performance: While all the content is still in the DOM, you can implement lazy loading for images or components within inactive tabs to speed up initial page load.
- Guided User Flow: Tabs can guide a user through a process or a set of related options in a structured manner.
Prerequisites: What You'll Need
This guide is beginner-friendly, but a basic understanding of the web's core technologies will be helpful. No frameworks needed!
- HTML: Basic knowledge of elements and attributes.
- CSS: Familiarity with selectors, properties, and the box model.
- JavaScript: Understanding of variables, functions, and DOM manipulation (like
querySelector
andaddEventListener
). - A code editor of your choice (like VS Code).
The 3-Step Guide to Creating JS Tabs
Alright, let's get to the fun part. We'll build our tabs from the ground up, starting with the structure.
Step 1: The HTML Structure (The Skeleton)
A good tab component consists of two main parts: the tab controls (the buttons you click) and the tab panels (the content that is shown/hidden). We need a way to link each control to its corresponding panel. The most robust way to do this is with data-*
attributes.
Here's a clean, semantic structure. Notice how each button's data-tab-target
attribute uses a CSS selector (#panel-1
) to point to the ID of its content panel.
<div class="tabs-container">
<ul class="tab-list">
<li class="tab-control active" data-tab-target="#panel-1">Profile</li>
<li class="tab-control" data-tab-target="#panel-2">Settings</li>
<li class="tab-control" data-tab-target="#panel-3">Billing</li>
</ul>
<div class="tab-content">
<div id="panel-1" class="tab-panel active">
<h4>Profile Information</h4>
<p>This is the content for the user's profile...</p>
</div>
<div id="panel-2" class="tab-panel">
<h4>Account Settings</h4>
<p>Here you can change your password and notification preferences...</p>
</div>
<div id="panel-3" class="tab-panel">
<h4>Billing Details</h4>
<p>View your payment history and current subscription...</p>
</div>
</div>
</div>
We've preemptively added an active
class to the first tab and its panel. This sets the default state when the page loads.
Step 2: The CSS Styling (The Look)
Now, let's make our structure look like actual tabs. The key here is to hide all panels by default and then use the .active
class to show the selected one.
/* Basic container styling */
.tabs-container {
width: 100%;
max-width: 600px;
margin: 2rem auto;
font-family: sans-serif;
}
/* Style for the list of tab controls */
.tab-list {
display: flex;
list-style-type: none;
margin: 0;
padding: 0;
border-bottom: 2px solid #ccc;
}
/* Style for each individual tab control */
.tab-control {
padding: 10px 20px;
cursor: pointer;
background-color: #f1f1f1;
border: 1px solid #ccc;
border-bottom: none;
border-radius: 5px 5px 0 0;
position: relative;
bottom: -2px; /* Aligns with the container's bottom border */
}
.tab-control:hover {
background-color: #ddd;
}
/* Style for the ACTIVE tab control */
.tab-control.active {
background-color: #fff;
border-bottom: 2px solid #fff; /* Creates the 'cutout' effect */
font-weight: bold;
}
/* The container for all panels */
.tab-content {
border: 2px solid #ccc;
padding: 20px;
border-top: none;
border-radius: 0 0 5px 5px;
}
/* CRITICAL: Hide all panels by default */
.tab-panel {
display: none;
}
/* CRITICAL: Show the active panel */
.tab-panel.active {
display: block;
}
The magic happens with display: none;
and display: block;
. Our JavaScript will simply toggle the .active
class to control which panel is visible.
Step 3: The JavaScript Magic (The Brains)
This is where we bring our tabs to life. The logic is straightforward: when a tab control is clicked, we need to update the active
classes on both the controls and the panels.
Here's the plan:
- Select all tab controls.
- Add a click event listener to each one.
- When a tab is clicked:
- Find the target panel using its
data-tab-target
attribute. - First, remove the
active
class from ALL tabs and ALL panels. This is a crucial reset step. - Then, add the
active
class to the tab that was just clicked and its corresponding panel.
document.addEventListener('DOMContentLoaded', () => {
// Select all elements with the class 'tab-control'
const tabControls = document.querySelectorAll('.tab-control');
// Add a click event listener to each tab control
tabControls.forEach(clickedTab => {
clickedTab.addEventListener('click', () => {
// 1. Get all tab controls and panels
const allTabs = document.querySelectorAll('.tab-control');
const allPanels = document.querySelectorAll('.tab-panel');
// 2. Remove 'active' class from all tabs and panels (the reset)
allTabs.forEach(tab => tab.classList.remove('active'));
allPanels.forEach(panel => panel.classList.remove('active'));
// 3. Add 'active' class to the clicked tab
clickedTab.classList.add('active');
// 4. Find and activate the corresponding tab panel
const targetPanelId = clickedTab.dataset.tabTarget;
const targetPanel = document.querySelector(targetPanelId);
if (targetPanel) {
targetPanel.classList.add('active');
}
});
});
});
And that's it! With this code, your tabs are fully functional.
Bonus: Making Your Tabs Accessible with ARIA
In 2025, functionality isn't enough. We must build for everyone. Accessible Rich Internet Applications (ARIA) roles and attributes help screen readers understand the purpose and state of our tabs. It's a small change to the HTML that makes a huge difference.
Key ARIA Attributes for Tabs:
role="tablist"
: On the container of the tab controls (our<ul>
). Tells screen readers this is a list of tabs.role="tab"
: On each tab control (our<li>
). Identifies it as a single tab.aria-selected="true/false"
: On each tab control. Explicitly states whether the tab is currently selected.role="tabpanel"
: On each content panel. Identifies it as a panel of content associated with a tab.aria-controls="panel-id"
: On each tab control, linking it programmatically to the panel it controls.
Let's update our HTML. We'll also need a tiny tweak to our JavaScript to handle the aria-selected
attribute.
Updated Accessible HTML:
<div class="tabs-container">
<ul class="tab-list" role="tablist">
<li class="tab-control active" role="tab" aria-selected="true" aria-controls="panel-1" data-tab-target="#panel-1">Profile</li>
<li class="tab-control" role="tab" aria-selected="false" aria-controls="panel-2" data-tab-target="#panel-2">Settings</li>
<li class="tab-control" role="tab" aria-selected="false" aria-controls="panel-3" data-tab-target="#panel-3">Billing</li>
</ul>
<div class="tab-content">
<div id="panel-1" class="tab-panel active" role="tabpanel">
<!-- Content -->
</div>
<div id="panel-2" class="tab-panel" role="tabpanel">
<!-- Content -->
</div>
<div id="panel-3" class="tab-panel" role="tabpanel">
<!-- Content -->
</div>
</div>
</div>
Updated JavaScript for ARIA:
// ... inside the event listener ...
// 2. Remove 'active' class and set aria-selected to false for all tabs
allTabs.forEach(tab => {
tab.classList.remove('active');
tab.setAttribute('aria-selected', 'false');
});
allPanels.forEach(panel => panel.classList.remove('active'));
// 3. Add 'active' class and set aria-selected to true for the clicked tab
clickedTab.classList.add('active');
clickedTab.setAttribute('aria-selected', 'true');
// ... rest of the code is the same ...
Putting It All Together: A Complete Example
Here is the full, final code combining the HTML, CSS, and updated JavaScript. You can copy and paste this into a single HTML file and open it in your browser to see it in action.
For a live, interactive version, check out this CodePen example. (Note: In a real blog, you would embed a CodePen here.)
<!-- Full code would be here, but is omitted for brevity. See the sections above. -->
Conclusion: You've Mastered Tabs!
And there you have it! You've gone from a blank page to a fully functional, styled, and accessible tab component in just three steps. You've seen how to structure the HTML, style it with CSS, and bring it to life with just a few lines of vanilla JavaScript.
The pattern you learned today—toggling an .active
class based on a user event—is one of the most fundamental concepts in frontend development. You can use it for accordions, modals, dropdowns, and more. Experiment with കൂടുതല് styling, add some CSS transitions for a smoother effect, and start using tabs to create cleaner, more intuitive interfaces in your projects.