Pure CSS Tabs Using :target Pseudo-Class
This tabbed interface is built entirely with HTML and CSS—no JavaScript required!
It uses the powerful :target pseudo-class to show and hide content
based on the URL hash.
💡 Pro Tip: Notice how the URL changes when you click tabs? This means you can bookmark specific tabs or share direct links to tab content!
The :target pseudo-class is supported in all modern browsers,
including Chrome, Firefox, Safari, Edge, and even Internet Explorer 9+.
The magic happens through a combination of hash links and the :target
pseudo-class. Here's the breakdown:
Each tab link points to a hash (fragment identifier) in the URL:
<a href="#overview">Overview</a>
<a href="#how-it-works">How It Works</a>
Each content panel has an id matching the hash:
<div id="overview" class="tab-panel">
Content here...
</div>
CSS uses :target to show the panel that matches the current URL hash:
.tab-panel {
display: none; /* Hide all panels by default */
}
.tab-panel:target {
display: block; /* Show the targeted panel */
animation: fadeIn 0.4s ease;
}
When you click a tab link, the URL changes to include the hash (e.g., #overview).
The browser then applies the :target pseudo-class to the element with that ID,
making it visible!
To show a default tab when no hash is present, we use:
.tab-panel:first-of-type {
display: block; /* Show first tab by default */
}
<div class="tabs">
<nav class="tab-nav">
<a href="#tab1" class="tab-link">Tab 1</a>
<a href="#tab2" class="tab-link">Tab 2</a>
</nav>
<div id="tab1" class="tab-panel">
Tab 1 content
</div>
<div id="tab2" class="tab-panel">
Tab 2 content
</div>
</div>
/* Hide all panels by default */
.tab-panel {
display: none;
}
/* Show targeted panel */
.tab-panel:target {
display: block;
}
/* Show first panel if no target */
.tab-panel:first-of-type {
display: block;
}
/* Hide first panel when another is targeted */
.tab-panel:target ~ .tab-panel:first-of-type {
display: none;
}
⚠️ Important: Each tab panel must have a unique id
that matches the href value in the corresponding tab link!
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.tab-panel:target {
animation: fadeIn 0.4s ease;
}
All colors are defined using CSS custom properties in the :root selector.
Find them at the top of the CSS (around line 70-85):
--color-primary - Main accent color--color-tab-active - Active tab background--color-tab-inactive - Inactive tab background--color-border - Border colors.tab-nav:
<a href="#newtab" class="tab-link">New Tab</a>
<div id="newtab" class="tab-panel">
Your content here
</div>
Try different animations by changing the keyframes:
translateY to translateXtransform: scale(0.95) in the from state0.2s or 0.6s)
✨ Challenge: Try creating vertical tabs by changing the .tab-nav
from flex-direction: row to flex-direction: column and adjusting
the layout!
<nav>, proper headings)
This template demonstrates concepts from Lesson 13: CSS Animations & Transitions.
The :target pseudo-class is a powerful tool for creating interactive UIs without JavaScript!
To view the complete source code, right-click anywhere on this page and select "View Page Source"
or press Ctrl+U (Windows/Linux) or Cmd+Option+U (Mac).