|$ curl https://forge-ai.dev/api/markdown?path=docs/components/tabs
$cat docs/tabs.md
updated Recently·18 min read·published

Tabs

CSSHTMLTailwindBootstrapUIIntermediate🎯Free Tools
Introduction

Tabs organize content into switchable sections without leaving the page. This guide covers production-ready tab patterns in plain HTML/CSS, Tailwind CSS, and Bootstrap — including underline, pill, filled, icon, vertical, and card variants, plus keyboard navigation and accessibility.

info

Always pair tabs with role="tablist", role="tab", and role="tabpanel". Use aria-selected on tabs and ensure only the active panel is visible to assistive tech.
Underline Tabs

Material-style underline tabs with a sliding indicator and ARIA roles.

underline-tabs
Live
untitled.html
HTML
1<div class="tabs-root">
2 <div class="tabs-list" role="tablist">
3 <button class="tab active" role="tab" aria-selected="true" data-tab="uprofile">
4 Profile
5 </button>
6 <button class="tab" role="tab" aria-selected="false" data-tab="usecurity">
7 Security
8 </button>
9 <button class="tab" role="tab" aria-selected="false" data-tab="ubilling">
10 Billing
11 </button>
12 <div class="indicator">
13 </div>
14 </div>
15 <div class="tab-panel active" id="uprofile" role="tabpanel">
16 <div class="panel-icon">
17 <svg viewBox="0 0 24 24" fill="none" stroke="#00FF41" stroke-width="2" width="24" height="24">
18 <path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/>
19 <circle cx="12" cy="7" r="4"/>
20 </svg>
21 </div>
22 <h3 class="panel-title">
23 Profile Settings
24 </h3>
25 <p class="panel-desc">
26 Manage your personal information and public profile.
27 </p>
28 </div>
29 <div class="tab-panel" id="usecurity" role="tabpanel">
30 <div class="panel-icon">
31 <svg viewBox="0 0 24 24" fill="none" stroke="#00FF41" stroke-width="2" width="24" height="24">
32 <rect x="3" y="11" width="18" height="11" rx="2" ry="2"/>
33 <path d="M7 11V7a5 5 0 0 1 10 0v4"/>
34 </svg>
35 </div>
36 <h3 class="panel-title">
37 Security
38 </h3>
39 <p class="panel-desc">
40 Configure password and two-factor authentication.
41 </p>
42 </div>
43 <div class="tab-panel" id="ubilling" role="tabpanel">
44 <div class="panel-icon">
45 <svg viewBox="0 0 24 24" fill="none" stroke="#00FF41" stroke-width="2" width="24" height="24">
46 <rect x="1" y="4" width="22" height="16" rx="2" ry="2"/>
47 <line x1="1" y1="10" x2="23" y2="10"/>
48 </svg>
49 </div>
50 <h3 class="panel-title">
51 Billing
52 </h3>
53 <p class="panel-desc">
54 View invoices and manage subscription plan.
55 </p>
56 </div>
57</div>
preview
Pill Tabs

Segmented pill tabs with icons — ideal for settings pages and compact filters.

pill-tabs
Live
untitled.html
HTML
1<div class="tabs-root">
2 <div class="pill-list" role="tablist">
3 <button class="pill active" role="tab" aria-selected="true" data-tab="ppreview">
4 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="14" height="14">
5 <rect x="3" y="3" width="7" height="7"/>
6 <rect x="14" y="3" width="7" height="7"/>
7 <rect x="14" y="14" width="7" height="7"/>
8 <rect x="3" y="14" width="7" height="7"/>
9 </svg>
10 Preview
11 </button>
12 <button class="pill" role="tab" aria-selected="false" data-tab="pcode">
13 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="14" height="14">
14 <polyline points="16 18 22 12 16 6"/>
15 <polyline points="8 6 2 12 8 18"/>
16 </svg>
17 Code
18 </button>
19 <button class="pill" role="tab" aria-selected="false" data-tab="poptions">
20 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="14" height="14">
21 <circle cx="12" cy="12" r="3"/>
22 <path d="M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42"/>
23 </svg>
24 Options
25 </button>
26 </div>
27 <div class="pill-panel active" id="ppreview" role="tabpanel">
28 <div class="preview-box">
29 <div class="preview-avatar">
30 </div>
31 <div class="preview-lines">
32 <div class="preview-line" style="width:60%">
33 </div>
34 <div class="preview-line" style="width:80%">
35 </div>
36 <div class="preview-line" style="width:40%">
37 </div>
38 </div>
39 </div>
40 </div>
41 <div class="pill-panel" id="pcode" role="tabpanel">
42 <pre class="code-block">
43 <span class="code-comment">
44 // main.js
45 </span>
46 <span class="code-line">
47 <span class="code-kw">
48 const
49 </span>
50 app =
51 <span class="code-fn">
52 initialize
53 </span>
54 ()
55 </span>
56 <span class="code-line">
57 app.
58 <span class="code-fn">
59 run
60 </span>
61 ({ mode:
62 <span class="code-str">
63 'dev'
64 </span>
65 })
66 </span>
67 </pre>
68 </div>
69 <div class="pill-panel" id="poptions" role="tabpanel">
70 <div class="toggle-list">
71 <label class="toggle-row">
72 <span>
73 Dark mode
74 </span>
75 <input type="checkbox" checked/>
76 </label>
77 <label class="toggle-row">
78 <span>
79 Auto-save
80 </span>
81 <input type="checkbox"/>
82 </label>
83 </div>
84 </div>
85</div>
preview
Filled Tabs

Solid background tabs with high-contrast active states — useful for dashboards and toolbars.

filled-tabs
Live
untitled.html
HTML
1<div class="tabs-root">
2 <div class="filled-list" role="tablist">
3 <button class="filled-tab active" role="tab" aria-selected="true" data-tab="fdash">
4 Dashboard
5 </button>
6 <button class="filled-tab" role="tab" aria-selected="false" data-tab="frepo">
7 Repositories
8 </button>
9 <button class="filled-tab" role="tab" aria-selected="false" data-tab="fdeploy">
10 Deployments
11 </button>
12 </div>
13 <div class="filled-panel active" id="fdash" role="tabpanel">
14 <div class="stat-grid">
15 <div class="stat">
16 <span class="stat-value">
17 24
18 </span>
19 <span class="stat-label">
20 Builds
21 </span>
22 </div>
23 <div class="stat">
24 <span class="stat-value">
25 98%
26 </span>
27 <span class="stat-label">
28 Uptime
29 </span>
30 </div>
31 <div class="stat">
32 <span class="stat-value">
33 3
34 </span>
35 <span class="stat-label">
36 Alerts
37 </span>
38 </div>
39 </div>
40 </div>
41 <div class="filled-panel" id="frepo" role="tabpanel">
42 <p class="panel-desc">
43 12 public and 4 private repositories synced.
44 </p>
45 </div>
46 <div class="filled-panel" id="fdeploy" role="tabpanel">
47 <p class="panel-desc">
48 Last deployment completed in 42 seconds.
49 </p>
50 </div>
51</div>
preview
Icon Tabs

Compact icon-only tabs and icon-plus-label tabs for toolbars and mobile navigation.

icon-tabs
Live
untitled.html
HTML
1<div class="tabs-root">
2 <div class="icon-list" role="tablist">
3 <button class="icon-tab active" role="tab" aria-selected="true" aria-label="Home" data-tab="ihome">
4 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="18" height="18">
5 <path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/>
6 <polyline points="9 22 9 12 15 12 15 22"/>
7 </svg>
8 <span>
9 Home
10 </span>
11 </button>
12 <button class="icon-tab" role="tab" aria-selected="false" aria-label="Search" data-tab="isearch">
13 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="18" height="18">
14 <circle cx="11" cy="11" r="8"/>
15 <line x1="21" y1="21" x2="16.65" y2="16.65"/>
16 </svg>
17 <span>
18 Search
19 </span>
20 </button>
21 <button class="icon-tab" role="tab" aria-selected="false" aria-label="Notifications" data-tab="inotif">
22 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="18" height="18">
23 <path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"/>
24 <path d="M13.73 21a2 2 0 0 1-3.46 0"/>
25 </svg>
26 <span>
27 Alerts
28 </span>
29 </button>
30 </div>
31 <div class="icon-panel active" id="ihome" role="tabpanel">
32 <p class="panel-desc">
33 Home dashboard overview.
34 </p>
35 </div>
36 <div class="icon-panel" id="isearch" role="tabpanel">
37 <p class="panel-desc">
38 Search across projects and files.
39 </p>
40 </div>
41 <div class="icon-panel" id="inotif" role="tabpanel">
42 <p class="panel-desc">
43 Notifications and mentions.
44 </p>
45 </div>
46</div>
preview
Vertical Tabs

Sidebar-style vertical tabs for settings panels and complex navigation layouts.

vertical-tabs
Live
untitled.html
HTML
1<div class="tabs-root">
2 <div class="v-list" role="tablist">
3 <button class="v-tab active" role="tab" aria-selected="true" data-tab="vgeneral">
4 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="16" height="16">
5 <path d="M12 20h9"/>
6 <path d="M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z"/>
7 </svg>
8 General
9 </button>
10 <button class="v-tab" role="tab" aria-selected="false" data-tab="vappearance">
11 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="16" height="16">
12 <circle cx="12" cy="12" r="3"/>
13 <path d="M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42"/>
14 </svg>
15 Appearance
16 </button>
17 <button class="v-tab" role="tab" aria-selected="false" data-tab="vadvanced">
18 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="16" height="16">
19 <circle cx="12" cy="12" r="3"/>
20 <path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"/>
21 </svg>
22 Advanced
23 </button>
24 </div>
25 <div class="v-body">
26 <div class="v-panel active" id="vgeneral" role="tabpanel">
27 <h3>
28 General Settings
29 </h3>
30 <label class="v-field">
31 <span>
32 Site Name
33 </span>
34 <input type="text" value="My App"/>
35 </label>
36 <label class="v-field">
37 <span>
38 Language
39 </span>
40 <select>
41 <option>
42 English
43 </option>
44 <option>
45 Spanish
46 </option>
47 </select>
48 </label>
49 </div>
50 <div class="v-panel" id="vappearance" role="tabpanel">
51 <h3>
52 Appearance
53 </h3>
54 <label class="v-field">
55 <span>
56 Theme
57 </span>
58 <select>
59 <option>
60 Dark
61 </option>
62 <option>
63 Light
64 </option>
65 </select>
66 </label>
67 <p class="v-desc">
68 Preview updates instantly.
69 </p>
70 </div>
71 <div class="v-panel" id="vadvanced" role="tabpanel">
72 <h3>
73 Advanced
74 </h3>
75 <label class="v-field">
76 <span>
77 API Key
78 </span>
79 <input type="password" value="sk-••••"/>
80 </label>
81 <p class="v-desc">
82 Rotate keys regularly.
83 </p>
84 </div>
85 </div>
86</div>
preview
Card Tabs

Tabs embedded inside a card component with rich content panels and clear visual separation.

card-tabs
Live
untitled.html
HTML
1<div class="card-root">
2 <div class="card-header">
3 <h2>
4 Project Settings
5 </h2>
6 <div class="card-tabs" role="tablist">
7 <button class="card-tab active" role="tab" aria-selected="true" data-tab="cdetails">
8 Details
9 </button>
10 <button class="card-tab" role="tab" aria-selected="false" data-tab="cmembers">
11 Members
12 </button>
13 <button class="card-tab" role="tab" aria-selected="false" data-tab="cintegrations">
14 Integrations
15 </button>
16 </div>
17 </div>
18 <div class="card-body">
19 <div class="card-panel active" id="cdetails" role="tabpanel">
20 <label class="field">
21 <span>
22 Project Name
23 </span>
24 <input type="text" value="forgelearn"/>
25 </label>
26 <label class="field">
27 <span>
28 Description
29 </span>
30 <textarea rows="2">
31 Engineering docs platform.
32 </textarea>
33 </label>
34 </div>
35 <div class="card-panel" id="cmembers" role="tabpanel">
36 <div class="member-list">
37 <div class="member">
38 <div class="member-avatar">
39 JD
40 </div>
41 <div>
42 <div class="member-name">
43 Jane Doe
44 </div>
45 <div class="member-role">
46 Owner
47 </div>
48 </div>
49 </div>
50 <div class="member">
51 <div class="member-avatar">
52 AS
53 </div>
54 <div>
55 <div class="member-name">
56 Alex Smith
57 </div>
58 <div class="member-role">
59 Editor
60 </div>
61 </div>
62 </div>
63 </div>
64 </div>
65 <div class="card-panel" id="cintegrations" role="tabpanel">
66 <div class="integration-list">
67 <div class="integration">
68 <svg viewBox="0 0 24 24" fill="none" stroke="#00FF41" stroke-width="2" width="18" height="18">
69 <path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"/>
70 </svg>
71 <span>
72 GitHub
73 </span>
74 <span class="badge">
75 Connected
76 </span>
77 </div>
78 <div class="integration">
79 <svg viewBox="0 0 24 24" fill="none" stroke="#00FF41" stroke-width="2" width="18" height="18">
80 <path d="M22 17H2a3 3 0 0 0 3-3V9a7 7 0 0 1 14 0v5a3 3 0 0 0 3 3zm-8.27 4a2 2 0 0 1-3.46 0"/>
81 </svg>
82 <span>
83 Slack
84 </span>
85 <span class="badge outline">
86 Connect
87 </span>
88 </div>
89 </div>
90 </div>
91 </div>
92</div>
preview
Accessibility

Tabs are interactive controls, so they must be keyboard operable and clearly announced by screen readers. Follow these practical guidelines for every tab pattern.

  • Use a real <button> for each tab so it is focusable and triggers with Enter/Space.
  • Wrap tabs in an element with role="tablist"; each tab needs role="tab".
  • Mark the active tab with aria-selected="true" and inactive tabs with aria-selected="false".
  • Give each content container role="tabpanel" and link it to the tab via aria-controls when possible.
  • Support ArrowLeft/ArrowRight keyboard navigation inside the tablist.
  • Ensure focus indicators are visible against the dark background.
  • Icon-only tabs require an aria-label on the button.

Community

Get help on Slack, Discord or VIP

Stuck on a guide? Join the community and ask.