{"id":2777,"date":"2026-02-06T06:52:18","date_gmt":"2026-02-06T06:52:18","guid":{"rendered":"https:\/\/demo.materiamedica.net\/demo6\/?p=2777"},"modified":"2026-02-06T06:52:18","modified_gmt":"2026-02-06T06:52:18","slug":"chapter-7-vertical-tabs","status":"publish","type":"post","link":"https:\/\/demo.materiamedica.net\/demo6\/chapter-7-vertical-tabs\/","title":{"rendered":"Chapter 7: Vertical Tabs"},"content":{"rendered":"<p dir=\"auto\">How to create <strong>vertical tabs<\/strong> (also called side tabs, left sidebar tabs, vertical tab navigation, etc.).<\/p>\n<p dir=\"auto\">Vertical tabs are very common in:<\/p>\n<ul dir=\"auto\">\n<li>Admin dashboards<\/li>\n<li>Settings pages<\/li>\n<li>Long forms \/ wizards<\/li>\n<li>Documentation sites<\/li>\n<li>Email clients \/ project management tools<\/li>\n<li>Desktop-style web applications<\/li>\n<\/ul>\n<p dir=\"auto\">Let\u2019s build them properly \u2014 from simple to professional \u2014 with clear explanations and real-world considerations.<\/p>\n<h3 dir=\"auto\">What makes good vertical tabs?<\/h3>\n<ul dir=\"auto\">\n<li>The active tab is clearly visible (color, border, background, icon\u2026)<\/li>\n<li>Tabs stay fixed or scroll with content (depending on design)<\/li>\n<li>Content area takes most of the space on the right<\/li>\n<li>Looks good on desktop \u2192 collapses gracefully on mobile (usually becomes horizontal tabs or accordion)<\/li>\n<li>Keyboard accessible<\/li>\n<li>Works with mouse, touch, and screen readers<\/li>\n<\/ul>\n<p dir=\"auto\">We\u2019ll create <strong>three versions<\/strong>:<\/p>\n<ol dir=\"auto\">\n<li>Simple &amp; clean vertical tabs (pure HTML + CSS + minimal JS)<\/li>\n<li>Responsive version (desktop vertical \u2192 mobile horizontal)<\/li>\n<li>Modern, accessible version with ARIA + smooth transitions<\/li>\n<\/ol>\n<h3 dir=\"auto\">Version 1 \u2013 Clean &amp; Classic Vertical Tabs<\/h3>\n<h4 dir=\"auto\">HTML Structure<\/h4>\n<div dir=\"auto\">\n<div data-testid=\"code-block\">\n<div>\n<div>HTML<\/div>\n<div>\n<pre tabindex=\"0\"><code>&lt;div class=\"vertical-tabs-container\"&gt;\r\n\r\n  &lt;!-- Left sidebar with tabs --&gt;\r\n  &lt;div class=\"tab-list\" role=\"tablist\"&gt;\r\n    &lt;button class=\"tab-btn active\" data-tab=\"overview\" aria-selected=\"true\" aria-controls=\"overview-panel\"&gt;\r\n      Overview\r\n    &lt;\/button&gt;\r\n    &lt;button class=\"tab-btn\" data-tab=\"profile\" aria-selected=\"false\" aria-controls=\"profile-panel\"&gt;\r\n      Profile\r\n    &lt;\/button&gt;\r\n    &lt;button class=\"tab-btn\" data-tab=\"account\" aria-selected=\"false\" aria-controls=\"account-panel\"&gt;\r\n      Account\r\n    &lt;\/button&gt;\r\n    &lt;button class=\"tab-btn\" data-tab=\"notifications\" aria-selected=\"false\" aria-controls=\"notifications-panel\"&gt;\r\n      Notifications\r\n    &lt;\/button&gt;\r\n    &lt;button class=\"tab-btn\" data-tab=\"security\" aria-selected=\"false\" aria-controls=\"security-panel\"&gt;\r\n      Security\r\n    &lt;\/button&gt;\r\n  &lt;\/div&gt;\r\n\r\n  &lt;!-- Right content area --&gt;\r\n  &lt;div class=\"tab-content-area\"&gt;\r\n    &lt;div class=\"tab-panel active\" id=\"overview-panel\" role=\"tabpanel\" aria-labelledby=\"overview-tab\"&gt;\r\n      &lt;h2&gt;Overview&lt;\/h2&gt;\r\n      &lt;p&gt;This is the dashboard overview. You can see quick stats, recent activity, and important alerts here.&lt;\/p&gt;\r\n    &lt;\/div&gt;\r\n\r\n    &lt;div class=\"tab-panel\" id=\"profile-panel\" role=\"tabpanel\" aria-labelledby=\"profile-tab\" hidden&gt;\r\n      &lt;h2&gt;Profile Information&lt;\/h2&gt;\r\n      &lt;p&gt;Update your name, photo, bio, job title, location, etc.&lt;\/p&gt;\r\n    &lt;\/div&gt;\r\n\r\n    &lt;div class=\"tab-panel\" id=\"account-panel\" role=\"tabpanel\" aria-labelledby=\"account-tab\" hidden&gt;\r\n      &lt;h2&gt;Account Settings&lt;\/h2&gt;\r\n      &lt;p&gt;Language, timezone, currency, dark mode preference...&lt;\/p&gt;\r\n    &lt;\/div&gt;\r\n\r\n    &lt;div class=\"tab-panel\" id=\"notifications-panel\" role=\"tabpanel\" aria-labelledby=\"notifications-tab\" hidden&gt;\r\n      &lt;h2&gt;Notification Preferences&lt;\/h2&gt;\r\n      &lt;p&gt;Choose what kind of notifications you want to receive and how.&lt;\/p&gt;\r\n    &lt;\/div&gt;\r\n\r\n    &lt;div class=\"tab-panel\" id=\"security-panel\" role=\"tabpanel\" aria-labelledby=\"security-tab\" hidden&gt;\r\n      &lt;h2&gt;Security &amp; Login&lt;\/h2&gt;\r\n      &lt;p&gt;Change password, enable 2FA, review login history, active sessions.&lt;\/p&gt;\r\n    &lt;\/div&gt;\r\n  &lt;\/div&gt;\r\n\r\n&lt;\/div&gt;<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<h4 dir=\"auto\">CSS (modern &amp; clean look)<\/h4>\n<div dir=\"auto\">\n<div data-testid=\"code-block\">\n<div>\n<div>CSS<\/div>\n<div>\n<pre tabindex=\"0\"><code>.vertical-tabs-container {\r\n  display: flex;\r\n  min-height: 500px;\r\n  max-width: 1100px;\r\n  margin: 2rem auto;\r\n  border: 1px solid #e5e5e5;\r\n  border-radius: 8px;\r\n  overflow: hidden;\r\n  font-family: system-ui, -apple-system, sans-serif;\r\n}\r\n\r\n.tab-list {\r\n  width: 240px;\r\n  background: #f8f9fa;\r\n  border-right: 1px solid #e5e5e5;\r\n  padding: 1.5rem 0;\r\n  flex-shrink: 0;\r\n}\r\n\r\n.tab-btn {\r\n  display: block;\r\n  width: 100%;\r\n  padding: 0.95rem 1.8rem;\r\n  text-align: left;\r\n  background: none;\r\n  border: none;\r\n  font-size: 1.03rem;\r\n  color: #444;\r\n  cursor: pointer;\r\n  transition: all 0.18s ease;\r\n}\r\n\r\n.tab-btn:hover {\r\n  background: #eef2ff;\r\n  color: #1e40af;\r\n}\r\n\r\n.tab-btn.active {\r\n  background: white;\r\n  color: #1d4ed8;\r\n  font-weight: 600;\r\n  border-right: 3px solid #3b82f6;\r\n  box-shadow: inset 3px 0 0 #3b82f6;\r\n  position: relative;\r\n}\r\n\r\n.tab-content-area {\r\n  flex: 1;\r\n  background: white;\r\n  padding: 2.2rem;\r\n}\r\n\r\n.tab-panel {\r\n  display: none;\r\n}\r\n\r\n.tab-panel.active {\r\n  display: block;\r\n}\r\n\r\n\/* Very subtle fade-in *\/\r\n.tab-panel {\r\n  opacity: 0;\r\n  transition: opacity 0.25s ease;\r\n}\r\n\r\n.tab-panel.active {\r\n  opacity: 1;\r\n}<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<h4 dir=\"auto\">JavaScript (minimal &amp; clean)<\/h4>\n<div dir=\"auto\">\n<div data-testid=\"code-block\">\n<div>\n<div>JavaScript<\/div>\n<div>\n<pre tabindex=\"0\"><code>document.addEventListener(\"DOMContentLoaded\", () =&gt; {\r\n  const buttons = document.querySelectorAll(\".tab-btn\");\r\n\r\n  buttons.forEach(btn =&gt; {\r\n    btn.addEventListener(\"click\", () =&gt; {\r\n      \/\/ Remove active from all\r\n      buttons.forEach(b =&gt; {\r\n        b.classList.remove(\"active\");\r\n        b.setAttribute(\"aria-selected\", \"false\");\r\n      });\r\n      document.querySelectorAll(\".tab-panel\").forEach(p =&gt; {\r\n        p.classList.remove(\"active\");\r\n        p.setAttribute(\"hidden\", \"\");\r\n      });\r\n\r\n      \/\/ Activate clicked tab\r\n      btn.classList.add(\"active\");\r\n      btn.setAttribute(\"aria-selected\", \"true\");\r\n\r\n      const panelId = btn.getAttribute(\"aria-controls\");\r\n      const panel = document.getElementById(panelId);\r\n      panel.classList.add(\"active\");\r\n      panel.removeAttribute(\"hidden\");\r\n    });\r\n  });\r\n});<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<h3 dir=\"auto\">Version 2 \u2013 Responsive (Desktop vertical \u2192 Mobile horizontal)<\/h3>\n<p dir=\"auto\">Add a media query to switch layout on small screens.<\/p>\n<div dir=\"auto\">\n<div data-testid=\"code-block\">\n<div>\n<div>CSS<\/div>\n<div>\n<pre tabindex=\"0\"><code>@media (max-width: 768px) {\r\n  .vertical-tabs-container {\r\n    flex-direction: column;\r\n  }\r\n\r\n  .tab-list {\r\n    width: 100%;\r\n    border-right: none;\r\n    border-bottom: 1px solid #e5e5e5;\r\n    display: flex;\r\n    overflow-x: auto;\r\n    padding: 0;\r\n    background: #fff;\r\n  }\r\n\r\n  .tab-btn {\r\n    flex: 0 0 auto;\r\n    padding: 1rem 1.4rem;\r\n    text-align: center;\r\n    white-space: nowrap;\r\n  }\r\n\r\n  .tab-btn.active {\r\n    border-right: none;\r\n    border-bottom: 3px solid #3b82f6;\r\n    box-shadow: none;\r\n  }\r\n\r\n  .tab-content-area {\r\n    padding: 1.5rem;\r\n  }\r\n}<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<p dir=\"auto\">Now on mobile the tabs become a horizontal scrollable bar \u2014 very common pattern.<\/p>\n<h3 dir=\"auto\">Version 3 \u2013 With Icons + Better Visual Feedback<\/h3>\n<p dir=\"auto\">Add icons (using Font Awesome or similar):<\/p>\n<div dir=\"auto\">\n<div data-testid=\"code-block\">\n<div>\n<div>HTML<\/div>\n<div>\n<pre tabindex=\"0\"><code>&lt;button class=\"tab-btn active\" data-tab=\"overview\" aria-selected=\"true\" aria-controls=\"overview-panel\"&gt;\r\n  &lt;i class=\"fas fa-home\"&gt;&lt;\/i&gt; Overview\r\n&lt;\/button&gt;\r\n&lt;button class=\"tab-btn\" data-tab=\"profile\" aria-selected=\"false\" aria-controls=\"profile-panel\"&gt;\r\n  &lt;i class=\"fas fa-user\"&gt;&lt;\/i&gt; Profile\r\n&lt;\/button&gt;\r\n&lt;button class=\"tab-btn\" data-tab=\"account\" aria-selected=\"false\" aria-controls=\"account-panel\"&gt;\r\n  &lt;i class=\"fas fa-cog\"&gt;&lt;\/i&gt; Account\r\n&lt;\/button&gt;\r\n...<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<p dir=\"auto\">CSS adjustment:<\/p>\n<div dir=\"auto\">\n<div data-testid=\"code-block\">\n<div>\n<div>CSS<\/div>\n<div>\n<pre tabindex=\"0\"><code>.tab-btn {\r\n  display: flex;\r\n  align-items: center;\r\n  gap: 12px;\r\n  padding: 1rem 1.6rem;\r\n}\r\n\r\n.tab-btn i {\r\n  width: 20px;\r\n  font-size: 1.15rem;\r\n  opacity: 0.7;\r\n}\r\n\r\n.tab-btn.active i {\r\n  opacity: 1;\r\n}<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<h3 dir=\"auto\">Important Things Good Developers Always Consider<\/h3>\n<ol dir=\"auto\">\n<li><strong>Active indicator<\/strong> Most common options: left border, background color, text color + bold, subtle shadow<\/li>\n<li><strong>Minimum touch\/click target<\/strong> Buttons should be at least <strong>44\u00d744 px<\/strong> (mobile) \u2014 we usually make them taller (52\u201360 px)<\/li>\n<li><strong>Keyboard navigation<\/strong>\n<ul dir=\"auto\">\n<li>Tab key should move between tab buttons<\/li>\n<li>Arrow keys can move focus between tabs (optional but nice)<\/li>\n<\/ul>\n<\/li>\n<li><strong>Mobile behavior<\/strong>\n<ul dir=\"auto\">\n<li>Horizontal scrollable tabs<\/li>\n<li>OR collapse to accordion (using &lt;details&gt;)<\/li>\n<\/ul>\n<\/li>\n<li><strong>Lazy loading<\/strong> (advanced) Only load content of the active tab \u2014 useful for heavy dashboards<\/li>\n<li><strong>Sticky tabs<\/strong> (sometimes) If the tab list is long, you can make it position: sticky; top: 0;<\/li>\n<\/ol>\n<h3 dir=\"auto\">Quick Checklist Before You Finish<\/h3>\n<ul dir=\"auto\">\n<li>Clear visual difference for active tab<\/li>\n<li>Enough padding &amp; spacing<\/li>\n<li>Works on mobile (test at 320\u2013768 px)<\/li>\n<li>Keyboard focus is visible<\/li>\n<li>aria-selected and aria-controls are correct<\/li>\n<li>role=&#8221;tablist&#8221;, role=&#8221;tab&#8221;, role=&#8221;tabpanel&#8221; used<\/li>\n<\/ul>\n<p dir=\"auto\">Would you like to go deeper into any of these next topics?<\/p>\n<p dir=\"auto\">Examples:<\/p>\n<ul dir=\"auto\">\n<li>How to make vertical tabs <strong>sticky<\/strong> when scrolling<\/li>\n<li>How to turn vertical tabs into <strong>accordion on mobile<\/strong><\/li>\n<li>How to add <strong>smooth slide\/fade animation<\/strong><\/li>\n<li>How to make <strong>icon-only tabs<\/strong> with tooltips<\/li>\n<li>How to handle <strong>very long tab lists<\/strong> (scrollable sidebar)<\/li>\n<li>How to do vertical tabs in <strong>Tailwind CSS<\/strong><\/li>\n<li>How to make <strong>nested \/ sub-tabs<\/strong> inside a tab<\/li>\n<\/ul>\n<p dir=\"auto\">Just tell me what you want next \u2014 I\u2019ll explain it slowly with complete code examples. \ud83d\ude0a<\/p>\n","protected":false},"excerpt":{"rendered":"<p>How to create vertical tabs (also called side tabs, left sidebar tabs, vertical tab navigation, etc.). Vertical tabs are very common in: Admin dashboards Settings pages Long forms \/ wizards Documentation sites Email clients&#46;&#46;&#46;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[77],"tags":[],"class_list":["post-2777","post","type-post","status-publish","format-standard","hentry","category-how-to"],"_links":{"self":[{"href":"https:\/\/demo.materiamedica.net\/demo6\/wp-json\/wp\/v2\/posts\/2777","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/demo.materiamedica.net\/demo6\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/demo.materiamedica.net\/demo6\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/demo.materiamedica.net\/demo6\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/demo.materiamedica.net\/demo6\/wp-json\/wp\/v2\/comments?post=2777"}],"version-history":[{"count":1,"href":"https:\/\/demo.materiamedica.net\/demo6\/wp-json\/wp\/v2\/posts\/2777\/revisions"}],"predecessor-version":[{"id":2778,"href":"https:\/\/demo.materiamedica.net\/demo6\/wp-json\/wp\/v2\/posts\/2777\/revisions\/2778"}],"wp:attachment":[{"href":"https:\/\/demo.materiamedica.net\/demo6\/wp-json\/wp\/v2\/media?parent=2777"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/demo.materiamedica.net\/demo6\/wp-json\/wp\/v2\/categories?post=2777"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/demo.materiamedica.net\/demo6\/wp-json\/wp\/v2\/tags?post=2777"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}