Chapter 8: Tab Headers
Tab Headers — that is, the clickable row / bar / list of titles that users actually click to switch between tabs.
Many people think “tabs” = the whole thing (headers + content), but today we’ll focus specifically on the tab headers themselves — how to design them, how to style them beautifully, how to make them behave well, and how to avoid the most common beginner mistakes.
What exactly are “Tab Headers”?
The tab headers are:
- The list of clickable items (usually buttons or links)
- Usually displayed horizontally (top tabs) or vertically (side tabs)
- Show the name of each tab (“Profile”, “Settings”, “Billing”, “Security”…)
- One of them is visually active / selected
- They usually have hover, focus, and active states
Goals of good tab headers (very important mindset)
- Instantly show which tab is currently selected
- Make it easy to click/tap (good size, spacing, touch target)
- Look clean and professional on both desktop and mobile
- Give clear visual feedback on hover and focus (accessibility!)
- Behave predictably (clicking another tab should clearly switch)
- Work well with keyboard navigation (Tab key + Enter/Space)
Let’s build tab headers in several common styles — from basic to modern.
Style 1 – Classic Underline Style (most common 2024–2026)
This is the style you see on GitHub, Stripe, Tailwind docs, many admin panels…
HTML
|
0 1 2 3 4 5 6 7 8 9 10 11 12 |
<div class="tab-headers"> <button class="tab-header active" data-tab="overview">Overview</button> <button class="tab-header" data-tab="features">Features</button> <button class="tab-header" data-tab="pricing">Pricing</button> <button class="tab-header" data-tab="reviews">Reviews</button> <button class="tab-header" data-tab="faq">FAQ</button> </div> |
CSS
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
.tab-headers { display: flex; border-bottom: 2px solid #e5e7eb; /* light gray line */ margin-bottom: 1.5rem; gap: 4px; /* small spacing between tabs */ overflow-x: auto; /* scrollable on mobile if too many */ padding-bottom: 2px; /* so underline doesn't touch content */ scrollbar-width: none; /* hide scrollbar in Firefox */ } .tab-headers::-webkit-scrollbar { display: none; /* hide scrollbar in Chrome/Safari */ } .tab-header { position: relative; padding: 0.85rem 1.4rem; font-size: 1.03rem; font-weight: 500; color: #4b5563; /* gray-600 */ background: none; border: none; cursor: pointer; white-space: nowrap; transition: color 0.15s ease; } .tab-header:hover { color: #1f2937; /* darker gray on hover */ } .tab-header:focus-visible { outline: none; box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.3); /* blue focus ring */ } .tab-header.active { color: #2563eb; /* blue-600 */ font-weight: 600; } /* The famous moving underline */ .tab-header.active::after { content: ""; position: absolute; bottom: -2px; left: 0; right: 0; height: 3px; background: #2563eb; border-radius: 3px 3px 0 0; } |
Important details:
- position: relative + ::after pseudo-element = clean moving underline
- overflow-x: auto + hide scrollbar = mobile-friendly
- white-space: nowrap prevents wrapping on small screens
- Good focus style for keyboard users
Style 2 – Pill / Rounded Background Style
Very popular in mobile-first designs, dashboards, settings pages…
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
.tab-headers { display: flex; gap: 8px; background: #f3f4f6; padding: 6px; border-radius: 12px; width: fit-content; margin: 0 auto 2rem; } .tab-header { padding: 0.75rem 1.4rem; border-radius: 10px; font-weight: 500; color: #4b5563; background: transparent; border: none; cursor: pointer; transition: all 0.2s ease; } .tab-header:hover { background: rgba(255, 255, 255, 0.7); color: #1f2937; } .tab-header.active { background: white; color: #1e40af; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); font-weight: 600; } |
Characteristics:
- Looks modern and “card-like”
- Great contrast between active and inactive
- Very touch-friendly
- Works well with dark mode (just change colors)
Style 3 – Bordered / Segmented Control Style
Looks like old-school segmented buttons — still very popular
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
.tab-headers { display: inline-flex; border: 1px solid #d1d5db; border-radius: 8px; overflow: hidden; background: white; } .tab-header { padding: 0.75rem 1.6rem; border: none; background: transparent; font-weight: 500; color: #4b5563; cursor: pointer; transition: all 0.15s; border-right: 1px solid #d1d5db; } .tab-header:last-child { border-right: none; } .tab-header:hover { background: #f9fafb; } .tab-header.active { background: #eff6ff; color: #1d4ed8; font-weight: 600; } |
Style 4 – Icon + Text (very common in dashboards)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<div class="tab-headers"> <button class="tab-header active"> <i class="fas fa-home"></i> <span>Dashboard</span> </button> <button class="tab-header"> <i class="fas fa-users"></i> <span>Team</span> </button> <button class="tab-header"> <i class="fas fa-chart-line"></i> <span>Analytics</span> </button> ... </div> |
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
.tab-header { display: flex; align-items: center; gap: 10px; padding: 0.9rem 1.5rem; } .tab-header i { font-size: 1.15rem; opacity: 0.7; } .tab-header.active i { opacity: 1; } |
Quick Checklist – Things Experienced Developers Always Check
- Minimum click/touch target ≈ 44×44 px (padding helps)
- Clear active state (underline, background, color, bold…)
- Visible focus style (never remove outline completely)
- Hover feedback (but not too dramatic)
- Scrollable on mobile when many tabs
- No wrapping on small screens (white-space: nowrap)
- Good contrast between active/inactive text
- Works in dark mode (test colors)
Common Beginner Mistakes & Fixes
| Mistake | Fix |
|---|---|
| No active indicator | Always show underline / background / bold |
| Tabs wrap to next line | flex-wrap: nowrap + overflow-x: auto |
| No hover/focus state | Add subtle background or color change |
| Too small tap area | Increase padding (0.8–1.2rem) |
| No keyboard focus visible | Add focus-visible style |
| Using <a> instead of <button> | Use <button> unless it’s real navigation |
Your next practice exercises
- Create tab headers with icons only + tooltip on hover
- Make the underline animate smoothly from one tab to another
- Create vertical tab headers (left sidebar style)
- Make tab headers change to pills on mobile
- Add disabled state to one tab (grayed out, no click)
Would you like me to explain any of these next topics in detail with complete code?
Examples:
- How to animate the underline sliding between tabs
- How to make icon-only tabs with tooltips
- How to make vertical tab headers
- How to handle too many tabs (scroll + arrows)
- How to style tab headers in Tailwind CSS
- How to make them look like browser tabs
- Common accessibility improvements
Just tell me which direction you want to go — I’ll go just as slowly and clearly. 😊
