22 CSS Dropdown Menu Designs21 / 22

CSS + JSMIT licensed

Tab Panel Dropdown

A dropdown that contains a full tabbed interface inside it, letting users switch between content panels without leaving the nav.

Published

Live Demo
Try it

The code

<div class="dd-21">
  <link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700&display=swap" rel="stylesheet">
  <nav class="dd-21__nav">
    <span class="dd-21__brand">&#9672; Mosaic</span>
    <div class="dd-21__items">
      <div class="dd-21__item">
        <button class="dd-21__trigger" id="dd-21-btn" aria-expanded="false">
          Explore ▾
        </button>
        <div class="dd-21__drop" id="dd-21-drop">
          <div class="dd-21__tabs" role="tablist" aria-label="Explore sections">
            <button class="dd-21__tab is-active" role="tab" aria-selected="true" data-panel="dd-21-p1">Popular</button>
            <button class="dd-21__tab" role="tab" aria-selected="false" data-panel="dd-21-p2">New</button>
            <button class="dd-21__tab" role="tab" aria-selected="false" data-panel="dd-21-p3">Topics</button>
          </div>
          <div class="dd-21__panels">
            <div class="dd-21__panel" id="dd-21-p1" role="tabpanel">
              <a href="#" class="dd-21__plink">&#128293; Most Visited</a>
              <a href="#" class="dd-21__plink">&#127775; Editor Picks</a>
              <a href="#" class="dd-21__plink">&#128202; Trending Now</a>
              <a href="#" class="dd-21__plink">&#127942; All-Time Best</a>
            </div>
            <div class="dd-21__panel is-hidden" id="dd-21-p2" role="tabpanel">
              <a href="#" class="dd-21__plink">&#128640; Just Launched</a>
              <a href="#" class="dd-21__plink">&#128336; This Week</a>
              <a href="#" class="dd-21__plink">&#128197; This Month</a>
              <a href="#" class="dd-21__plink">&#127381; Coming Soon</a>
            </div>
            <div class="dd-21__panel is-hidden" id="dd-21-p3" role="tabpanel">
              <a href="#" class="dd-21__plink">&#127775; Design</a>
              <a href="#" class="dd-21__plink">&#128187; Engineering</a>
              <a href="#" class="dd-21__plink">&#128640; Product</a>
              <a href="#" class="dd-21__plink">&#128218; Business</a>
            </div>
          </div>
        </div>
      </div>
      <a href="#" class="dd-21__plain">Pricing</a>
      <a href="#" class="dd-21__plain">Blog</a>
    </div>
  </nav>
</div>
.dd-21,
.dd-21 *,
.dd-21 *::before,
.dd-21 *::after {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

.dd-21 ::selection {
  background: #10b981;
  color: #fff;
}

.dd-21 {
  --brand: #10b981;
  --surface: #fff;
  --text: #064e3b;
  --muted: #6b7280;
  --border: #d1fae5;
  --hover: #ecfdf5;
  font-family: 'Plus Jakarta Sans', sans-serif;
  min-height: 380px;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: 32px 20px;
  background: linear-gradient(135deg, #ecfdf5 0%, #d1fae5 100%);
}

.dd-21__nav {
  display: flex;
  align-items: center;
  gap: 4px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 10px 10px 10px 20px;
  box-shadow: 0 4px 24px rgba(16,185,129,.12);
  position: relative;
  z-index: 100;
  width: 100%;
  max-width: 600px;
}

.dd-21__brand {
  font-size: 17px;
  font-weight: 700;
  color: var(--brand);
  margin-right: 12px;
}

.dd-21__items {
  display: flex;
  align-items: center;
  gap: 4px;
}

.dd-21__item {
  position: relative;
}

.dd-21__trigger {
  padding: 8px 14px;
  border: none;
  background: none;
  cursor: pointer;
  font-family: inherit;
  font-size: 14px;
  font-weight: 600;
  color: var(--text);
  border-radius: 8px;
  transition: background 0.15s;
}

.dd-21__trigger:hover {
  background: var(--hover);
}

.dd-21__trigger[aria-expanded="true"] {
  background: var(--hover);
  color: var(--brand);
}

.dd-21__plain {
  padding: 8px 14px;
  color: var(--muted);
  text-decoration: none;
  font-size: 14px;
  font-weight: 500;
  border-radius: 8px;
  transition: background 0.15s, color 0.15s;
}

.dd-21__plain:hover {
  background: var(--hover);
  color: var(--text);
}

.dd-21__drop {
  position: absolute;
  top: calc(100% + 10px);
  left: 0;
  width: 260px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 14px;
  box-shadow: 0 12px 40px rgba(16,185,129,.14);
  overflow: hidden;
  opacity: 0;
  pointer-events: none;
  transform: translateY(-8px);
  transition: opacity 0.22s ease, transform 0.28s cubic-bezier(0.16, 1, 0.3, 1);
}

.dd-21__drop.is-open {
  opacity: 1;
  pointer-events: auto;
  transform: translateY(0);
}

.dd-21__tabs {
  display: flex;
  border-bottom: 1px solid var(--border);
  padding: 6px 6px 0;
  gap: 2px;
}

.dd-21__tab {
  flex: 1;
  padding: 8px 6px;
  border: none;
  border-radius: 8px 8px 0 0;
  background: transparent;
  cursor: pointer;
  font-family: inherit;
  font-size: 13px;
  font-weight: 600;
  color: var(--muted);
  border-bottom: 2px solid transparent;
  transition: color 0.15s, background 0.15s;
  position: relative;
  bottom: -1px;
}

.dd-21__tab:hover {
  color: var(--text);
  background: #f0fdf4;
}

.dd-21__tab.is-active {
  color: var(--brand);
  border-bottom-color: var(--brand);
  background: #f0fdf4;
}

.dd-21__panels {
  padding: 6px;
  min-height: 140px;
}

.dd-21__panel {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.dd-21__panel.is-hidden {
  display: none;
}

@keyframes dd-21-fadein {
  from {
    opacity: 0;
    transform: translateY(4px);
  }

  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.dd-21__panel:not(.is-hidden) {
  animation: dd-21-fadein 0.22s ease;
}

.dd-21__plink {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 9px 12px;
  border-radius: 9px;
  text-decoration: none;
  color: var(--text);
  font-size: 13.5px;
  font-weight: 500;
  transition: background 0.12s;
}

.dd-21__plink:hover {
  background: var(--hover);
  color: var(--brand);
}

@media (prefers-reduced-motion: reduce) {
  .dd-21__drop,
    .dd-21__tab,
    .dd-21__panel {
    transition: none;
    animation: none;
  }
}
(function() {
  var btn  = document.getElementById('dd-21-btn');
  var drop = document.getElementById('dd-21-drop');
  if (!btn || !drop) return;
  var tabs   = Array.from(drop.querySelectorAll('.dd-21__tab'));
  var panels = Array.from(drop.querySelectorAll('.dd-21__panel'));

  function activateTab(tab) {
    tabs.forEach(function(t) { t.classList.remove('is-active'); t.setAttribute('aria-selected', 'false'); });
    panels.forEach(function(p) { p.classList.add('is-hidden'); });
    tab.classList.add('is-active');
    tab.setAttribute('aria-selected', 'true');
    var target = document.getElementById(tab.dataset.panel);
    if (target) target.classList.remove('is-hidden');
  }

  tabs.forEach(function(tab) { tab.addEventListener('click', function() { activateTab(tab); }); });

  btn.addEventListener('click', function(e) {
    e.stopPropagation();
    var open = drop.classList.toggle('is-open');
    btn.setAttribute('aria-expanded', open ? 'true' : 'false');
  });

  document.addEventListener('click', function(e) {
    if (!drop.contains(e.target) && e.target !== btn) {
      drop.classList.remove('is-open');
      btn.setAttribute('aria-expanded', 'false');
    }
  });

  document.addEventListener('keydown', function(e) {
    if (e.key === 'Escape') { drop.classList.remove('is-open'); btn.setAttribute('aria-expanded', 'false'); }
  });
})();
Paste this into ChatGPT, Claude, Cursor, or any coding assistant. The block below is pre-framed with everything the AI needs to integrate this demo into your project — markup, styles, scoping notes, and the source URL. Hit Copy and paste straight into your chat.
Here's a working CSS Dropdown Menu Design from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Tab Panel Dropdown
Source: https://codefronts.com/navigation/css-dropdown-menus/tab-panel-dropdown/

A dropdown that contains a full tabbed interface inside it, letting users switch between content panels without leaving the nav.
## HTML
```html
<div class="dd-21">
  <link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700&display=swap" rel="stylesheet">
  <nav class="dd-21__nav">
    <span class="dd-21__brand">&#9672; Mosaic</span>
    <div class="dd-21__items">
      <div class="dd-21__item">
        <button class="dd-21__trigger" id="dd-21-btn" aria-expanded="false">
          Explore ▾
        </button>
        <div class="dd-21__drop" id="dd-21-drop">
          <div class="dd-21__tabs" role="tablist" aria-label="Explore sections">
            <button class="dd-21__tab is-active" role="tab" aria-selected="true" data-panel="dd-21-p1">Popular</button>
            <button class="dd-21__tab" role="tab" aria-selected="false" data-panel="dd-21-p2">New</button>
            <button class="dd-21__tab" role="tab" aria-selected="false" data-panel="dd-21-p3">Topics</button>
          </div>
          <div class="dd-21__panels">
            <div class="dd-21__panel" id="dd-21-p1" role="tabpanel">
              <a href="#" class="dd-21__plink">&#128293; Most Visited</a>
              <a href="#" class="dd-21__plink">&#127775; Editor Picks</a>
              <a href="#" class="dd-21__plink">&#128202; Trending Now</a>
              <a href="#" class="dd-21__plink">&#127942; All-Time Best</a>
            </div>
            <div class="dd-21__panel is-hidden" id="dd-21-p2" role="tabpanel">
              <a href="#" class="dd-21__plink">&#128640; Just Launched</a>
              <a href="#" class="dd-21__plink">&#128336; This Week</a>
              <a href="#" class="dd-21__plink">&#128197; This Month</a>
              <a href="#" class="dd-21__plink">&#127381; Coming Soon</a>
            </div>
            <div class="dd-21__panel is-hidden" id="dd-21-p3" role="tabpanel">
              <a href="#" class="dd-21__plink">&#127775; Design</a>
              <a href="#" class="dd-21__plink">&#128187; Engineering</a>
              <a href="#" class="dd-21__plink">&#128640; Product</a>
              <a href="#" class="dd-21__plink">&#128218; Business</a>
            </div>
          </div>
        </div>
      </div>
      <a href="#" class="dd-21__plain">Pricing</a>
      <a href="#" class="dd-21__plain">Blog</a>
    </div>
  </nav>
</div>
```
## CSS
```css
.dd-21,
.dd-21 *,
.dd-21 *::before,
.dd-21 *::after {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

.dd-21 ::selection {
  background: #10b981;
  color: #fff;
}

.dd-21 {
  --brand: #10b981;
  --surface: #fff;
  --text: #064e3b;
  --muted: #6b7280;
  --border: #d1fae5;
  --hover: #ecfdf5;
  font-family: 'Plus Jakarta Sans', sans-serif;
  min-height: 380px;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: 32px 20px;
  background: linear-gradient(135deg, #ecfdf5 0%, #d1fae5 100%);
}

.dd-21__nav {
  display: flex;
  align-items: center;
  gap: 4px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 10px 10px 10px 20px;
  box-shadow: 0 4px 24px rgba(16,185,129,.12);
  position: relative;
  z-index: 100;
  width: 100%;
  max-width: 600px;
}

.dd-21__brand {
  font-size: 17px;
  font-weight: 700;
  color: var(--brand);
  margin-right: 12px;
}

.dd-21__items {
  display: flex;
  align-items: center;
  gap: 4px;
}

.dd-21__item {
  position: relative;
}

.dd-21__trigger {
  padding: 8px 14px;
  border: none;
  background: none;
  cursor: pointer;
  font-family: inherit;
  font-size: 14px;
  font-weight: 600;
  color: var(--text);
  border-radius: 8px;
  transition: background 0.15s;
}

.dd-21__trigger:hover {
  background: var(--hover);
}

.dd-21__trigger[aria-expanded="true"] {
  background: var(--hover);
  color: var(--brand);
}

.dd-21__plain {
  padding: 8px 14px;
  color: var(--muted);
  text-decoration: none;
  font-size: 14px;
  font-weight: 500;
  border-radius: 8px;
  transition: background 0.15s, color 0.15s;
}

.dd-21__plain:hover {
  background: var(--hover);
  color: var(--text);
}

.dd-21__drop {
  position: absolute;
  top: calc(100% + 10px);
  left: 0;
  width: 260px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 14px;
  box-shadow: 0 12px 40px rgba(16,185,129,.14);
  overflow: hidden;
  opacity: 0;
  pointer-events: none;
  transform: translateY(-8px);
  transition: opacity 0.22s ease, transform 0.28s cubic-bezier(0.16, 1, 0.3, 1);
}

.dd-21__drop.is-open {
  opacity: 1;
  pointer-events: auto;
  transform: translateY(0);
}

.dd-21__tabs {
  display: flex;
  border-bottom: 1px solid var(--border);
  padding: 6px 6px 0;
  gap: 2px;
}

.dd-21__tab {
  flex: 1;
  padding: 8px 6px;
  border: none;
  border-radius: 8px 8px 0 0;
  background: transparent;
  cursor: pointer;
  font-family: inherit;
  font-size: 13px;
  font-weight: 600;
  color: var(--muted);
  border-bottom: 2px solid transparent;
  transition: color 0.15s, background 0.15s;
  position: relative;
  bottom: -1px;
}

.dd-21__tab:hover {
  color: var(--text);
  background: #f0fdf4;
}

.dd-21__tab.is-active {
  color: var(--brand);
  border-bottom-color: var(--brand);
  background: #f0fdf4;
}

.dd-21__panels {
  padding: 6px;
  min-height: 140px;
}

.dd-21__panel {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.dd-21__panel.is-hidden {
  display: none;
}

@keyframes dd-21-fadein {
  from {
    opacity: 0;
    transform: translateY(4px);
  }

  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.dd-21__panel:not(.is-hidden) {
  animation: dd-21-fadein 0.22s ease;
}

.dd-21__plink {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 9px 12px;
  border-radius: 9px;
  text-decoration: none;
  color: var(--text);
  font-size: 13.5px;
  font-weight: 500;
  transition: background 0.12s;
}

.dd-21__plink:hover {
  background: var(--hover);
  color: var(--brand);
}

@media (prefers-reduced-motion: reduce) {
  .dd-21__drop,
    .dd-21__tab,
    .dd-21__panel {
    transition: none;
    animation: none;
  }
}
```

## JavaScript
```js
(function() {
  var btn  = document.getElementById('dd-21-btn');
  var drop = document.getElementById('dd-21-drop');
  if (!btn || !drop) return;
  var tabs   = Array.from(drop.querySelectorAll('.dd-21__tab'));
  var panels = Array.from(drop.querySelectorAll('.dd-21__panel'));

  function activateTab(tab) {
    tabs.forEach(function(t) { t.classList.remove('is-active'); t.setAttribute('aria-selected', 'false'); });
    panels.forEach(function(p) { p.classList.add('is-hidden'); });
    tab.classList.add('is-active');
    tab.setAttribute('aria-selected', 'true');
    var target = document.getElementById(tab.dataset.panel);
    if (target) target.classList.remove('is-hidden');
  }

  tabs.forEach(function(tab) { tab.addEventListener('click', function() { activateTab(tab); }); });

  btn.addEventListener('click', function(e) {
    e.stopPropagation();
    var open = drop.classList.toggle('is-open');
    btn.setAttribute('aria-expanded', open ? 'true' : 'false');
  });

  document.addEventListener('click', function(e) {
    if (!drop.contains(e.target) && e.target !== btn) {
      drop.classList.remove('is-open');
      btn.setAttribute('aria-expanded', 'false');
    }
  });

  document.addEventListener('keydown', function(e) {
    if (e.key === 'Escape') { drop.classList.remove('is-open'); btn.setAttribute('aria-expanded', 'false'); }
  });
})();
```

How this works

The dropdown panel contains a tab bar (.dd-21__tabs) and a panel area (.dd-21__panels). JavaScript attaches click listeners to each tab button. On click, all tabs lose is-active, the clicked tab gains it, all panels get the is-hidden class, and the target panel (matched by data-panelid) becomes visible with a fade-in animation.

The dropdown itself opens/closes by toggling an is-open class on the panel, triggered by a button click. An aria-selected attribute is toggled on tabs for accessibility. The role="tablist", role="tab", and role="tabpanel" ARIA pattern is applied so screen readers understand the tabbed widget inside the dropdown.

Make it yours

  • Make tabs scrollable for many tabs by adding overflow-x: auto; white-space: nowrap to the tab bar — useful for mobile-width panels.
  • Add a tab indicator line that slides between tabs using a JS-measured left and width on a single div element.
  • Persist the active tab across dropdown open/close sessions using a variable to track the last active tab index.
  • Add icons above each tab label for a richer visual hierarchy inside the dropdown.

Gotchas — read before shipping

  • Dropdown panels with dynamic content height can cause layout jumps — set a min-height on the panel container to prevent collapse when switching to shorter tabs.
  • Tab keyboard navigation (ArrowLeft/Right between tabs) is part of the ARIA tab pattern — without it, keyboard users must Tab through all content instead of using arrow keys.
  • If the dropdown is inside an ancestor with overflow: hidden, the absolute-positioned panel will be clipped — test in your actual layout.

Browser support

ChromeSafariFirefoxEdge
49+10+44+49+

Fully supported in all modern browsers; ARIA tab pattern announced by all major screen readers.

Techniques used in this demo

Search CodeFronts

Loading…