Tabs are one of those UI patterns you see everywhere — dashboards, settings pages, pricing sections,...
Tabs are one of those UI patterns you see everywhere — dashboards, settings pages, pricing sections, docs, etc.
In this post, we’ll build a fully working tab system using only HTML, CSS, and JavaScript.
## HTML Structure
The HTML Structure is minimalistic:
```html
<div class="tabbed-content">
<ul class="tabs" role="tablist">
<li role="tab" aria-selected="true" class="active">Tab 1</li>
<li role="tab" aria-selected="false">Tab 2</li>
<li role="tab" aria-selected="false">Tab 3</li>
</ul>
<div class="content">
<div class="show">
<h2>Tab 1 content</h2>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit.</p>
</div>
<div>
<h2>Tab 2 content</h2>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit.</p>
</div>
<div>
<h2>Tab 3 content</h2>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit.</p>
</div>
</div>
</div>
```
As you can see, on page load, the first tab has the class name _active_, and the first panel has the class name _show_. The `aria-selected` attribute helps with accessibility.
## The CSS Styling
```css
.tabbed-content {
margin: 10px auto;
max-width: 500px;
}
.tabs {
display: flex;
}
.tabs li {
flex: 1;
border: 1px solid #ddd;
border-radius: 4px 4px 0 0;
background: #eee;
cursor: pointer;
height: 36px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.tabs li.active {
border-bottom: 1px solid #fff;
background: #fff;
}
.content {
padding: 10px;
border: 1px solid #ddd;
border-top: none;
}
.content > div {
display: none;
}
.content > div.show {
display: block;
}
.content h2 {
font-size: 18px;
margin-bottom: 10px;
}
.content p {
font-size: 14px;
}
```
## The JavaScript Logic
```javascript
const tabbedContent = document.querySelector('.tabbed-content');
const tabs = tabbedContent.querySelectorAll('.tabs li');
const contentItems = tabbedContent.querySelectorAll('.content > div');
tabs.forEach((tab, index) => {
tab.addEventListener('click', () => {
// Reset all tabs
tabs.forEach((t) => {
t.classList.remove('active');
t.setAttribute('aria-selected', 'false');
});
// Hide all content
contentItems.forEach((item) => {
item.classList.remove('show');
});
// Activate clicked tab
tab.classList.add('active');
tab.setAttribute('aria-selected', 'true');
// Show matching content
contentItems[index].classList.add('show');
});
});
```
## How It Works
We match Tab 1 to Content 1, Tab 2 to Content 2, and Tab 3 to Content 3 by using `index`: `tabs.forEach((tab, index) => {})`. So when a tab is clicked, we show the corresponding panel with `contentItems[index].classList.add('show')`.
Before activating a new tab, we always reset everything using:
```javascript
tabs.forEach(t => {
t.classList.remove('active');
});
contentItems.forEach(item => {
item.classList.remove('show');
});
```
This ensures only one tab is active and only one panel is displayed at a time.
## Conclusion
In conclusion, each tab controls one content panel, and everything else is just state management.
No frameworks needed. You can take these tabs and style them as you need.