28 Tailwind Hamburger Menus
15 / 28

All 28 in 28 Tailwind Hamburger Menus

  1. 01Tailwind Hamburger Menu with Clip-Path Circle Expansion
  2. 02Tailwind Keyboard Navigable Hamburger Menu with ARIA Attributes
  3. 03Tailwind Animated 3-Line to X Hamburger Icon Toggle
  4. 04Tailwind Slide-In Off-Canvas Drawer with Dimmed Backdrop Overlay
  5. 05Pure Tailwind Checkbox Hack Hamburger Navigation (No JavaScript)
  6. 06Tailwind Responsive Hamburger Menu with Integrated Search Bar & Social Links
  7. 07Tailwind Glassmorphism Backdrop Blur Hamburger Navigation
  8. 08Tailwind Push Page Navigation Menu (Off-Canvas Content Shift)
  9. 09Pure Tailwind Hamburger Menu Without JavaScript
  10. 10Tailwind Hamburger Menu Morphing to Close Icon Animation
  11. 11Tailwind Full Screen Mobile Navigation Overlay
  12. 12Tailwind Slide Out Sidebar Navigation / Off Canvas Menu
  13. 13Tailwind Responsive Navbar Mobile Hamburger Toggle Breakpoints
  14. 14Tailwind Minimalist Floating Hamburger Button
  15. 15Tailwind CSS Responsive Hamburger Menu Component
  16. 16Tailwind Rebuild of the Bootstrap 5 Navbar Hamburger Toggle
  17. 17Tailwind WCAG Accessible Hamburger Menu Example
  18. 18Pure Tailwind Dropdown Slide Down Mobile Hamburger Menu
  19. 19Simple 3-Line Tailwind Hamburger Icon Hover Effect
  20. 20Tailwind Full Screen Blur Overlay Hamburger Menu
  21. 21Tailwind Mobile Bottom Navigation Bar with Floating Hamburger Toggle
  22. 22Pure Tailwind Multi-Level Accordion Hamburger Dropdown Menu
  23. 23Flexbox Navbar Right-Aligned Tailwind Hamburger Icon
  24. 24Radial Ripple Expand Tailwind Hamburger Menu
  25. 25Sticky Tailwind Navbar Shrinking Hamburger Icon on Scroll
  26. 26Neumorphic Tailwind Hamburger Toggle Button
  27. 27Brutalist Design Bordered Tailwind Hamburger Menu
  28. 28Tailwind 3D Flip Canvas Mobile Hamburger Navigation
Tailwind + JSMIT licensed

Tailwind CSS Responsive Hamburger Menu Component

The canonical Tailwind navbar — and in this collection it is the one demo that needed no port at all, because the original was already written in utilities. What it gains here is honesty: the CSS version had to ship a hand-written shim to render those classes, and this one runs the real compiler, so what you see is exactly what hidden md:flex produces.

Live Demo
Plain CSSTailwind v4
Try it

Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time

Untitled UI React · Affiliate link

Get Untitled UI Pro

The code

<section class="thb-15 w-full min-h-svh bg-thb15-bg font-thb15-sans text-thb15-ink px-5 py-9" aria-label="Tailwind CSS hamburger menu demo">
  <div class="grid gap-3.5 p-5 rounded-[18px] border border-thb15-edge bg-thb15-bg">
    <div class="@container overflow-hidden rounded-[14px] border border-thb15-edge bg-white shadow-[0_14px_34px_-26px_oklch(0.3_0.02_286/0.6)]">
      <nav class="flex items-center justify-between px-4 py-3 bg-white border-b border-thb15-edge" aria-label="Primary">
        <a href="#home" class="flex items-center gap-2 font-bold text-thb15-ink no-underline">
          <span class="w-4.5 h-4.5 rounded-md bg-[conic-gradient(from_200deg,var(--color-thb15-acc),oklch(0.72_0.14_190))]" aria-hidden="true"></span>tailfleet
        </a>
        <div class="hidden @md:flex @md:items-center @md:gap-1">
          <a href="#features" aria-current="page" class="inline-flex items-center min-h-9.5 px-3 rounded-[9px] text-[13.5px] font-semibold text-thb15-mut no-underline transition-[color,background] duration-150 hover:text-thb15-ink hover:bg-thb15-hover focus-visible:outline-2 focus-visible:outline-thb15-acc focus-visible:outline-offset-2 aria-current:text-thb15-acc">Features</a>
          <a href="#pricing" class="inline-flex items-center min-h-9.5 px-3 rounded-[9px] text-[13.5px] font-semibold text-thb15-mut no-underline transition-[color,background] duration-150 hover:text-thb15-ink hover:bg-thb15-hover focus-visible:outline-2 focus-visible:outline-thb15-acc focus-visible:outline-offset-2">Pricing</a>
          <a href="#docs" class="inline-flex items-center min-h-9.5 px-3 rounded-[9px] text-[13.5px] font-semibold text-thb15-mut no-underline transition-[color,background] duration-150 hover:text-thb15-ink hover:bg-thb15-hover focus-visible:outline-2 focus-visible:outline-thb15-acc focus-visible:outline-offset-2">Docs</a>
          <a href="#blog" class="inline-flex items-center min-h-9.5 px-3 rounded-[9px] text-[13.5px] font-semibold text-thb15-mut no-underline transition-[color,background] duration-150 hover:text-thb15-ink hover:bg-thb15-hover focus-visible:outline-2 focus-visible:outline-thb15-acc focus-visible:outline-offset-2">Blog</a>
        </div>
        <div class="flex items-center gap-2">
          <a href="#signup" class="hidden @md:inline-flex items-center min-h-10 px-4 rounded-[10px] bg-thb15-ink text-white text-[13px] font-bold no-underline transition-[background] duration-200 hover:bg-thb15-acc focus-visible:outline-2 focus-visible:outline-thb15-acc focus-visible:outline-offset-2">Sign up</a>
          <button type="button" aria-expanded="false" aria-controls="thb15-menu" aria-label="Open menu" class="thb15-burger grid place-items-center w-11 h-11 rounded-[10px] border border-thb15-edge bg-white text-thb15-ink cursor-pointer transition-[background] duration-150 hover:bg-thb15-hover focus-visible:outline-2 focus-visible:outline-thb15-acc focus-visible:outline-offset-2 @md:hidden">
            <svg class="thb15-open [grid-area:1/1]" viewBox="0 0 24 24" width="22" height="22" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><path d="M4 6h16M4 12h16M4 18h16"/></svg>
            <svg class="thb15-close hidden [grid-area:1/1]" viewBox="0 0 24 24" width="22" height="22" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><path d="m6 6 12 12M18 6 6 18"/></svg>
          </button>
        </div>
      </nav>
      <div id="thb15-menu" class="hidden px-3 pb-3 bg-white border-b border-thb15-edge @md:hidden">
        <a href="#features" aria-current="page" class="flex items-center min-h-11 px-3 rounded-[9px] text-sm font-semibold text-thb15-mut no-underline transition-[background,color] duration-150 hover:bg-thb15-hover hover:text-thb15-ink focus-visible:outline-2 focus-visible:outline-thb15-acc focus-visible:-outline-offset-2 aria-current:text-thb15-acc">Features</a>
        <a href="#pricing" class="flex items-center min-h-11 px-3 rounded-[9px] text-sm font-semibold text-thb15-mut no-underline transition-[background,color] duration-150 hover:bg-thb15-hover hover:text-thb15-ink focus-visible:outline-2 focus-visible:outline-thb15-acc focus-visible:-outline-offset-2">Pricing</a>
        <a href="#docs" class="flex items-center min-h-11 px-3 rounded-[9px] text-sm font-semibold text-thb15-mut no-underline transition-[background,color] duration-150 hover:bg-thb15-hover hover:text-thb15-ink focus-visible:outline-2 focus-visible:outline-thb15-acc focus-visible:-outline-offset-2">Docs</a>
        <a href="#blog" class="flex items-center min-h-11 px-3 rounded-[9px] text-sm font-semibold text-thb15-mut no-underline transition-[background,color] duration-150 hover:bg-thb15-hover hover:text-thb15-ink focus-visible:outline-2 focus-visible:outline-thb15-acc focus-visible:-outline-offset-2">Blog</a>
        <a href="#signup" class="flex items-center justify-center w-full min-h-10 mt-2 px-4 rounded-[10px] bg-thb15-ink text-white text-[13px] font-bold no-underline transition-[background] duration-200 hover:bg-thb15-acc focus-visible:outline-2 focus-visible:outline-thb15-acc focus-visible:outline-offset-2">Sign up</a>
      </div>
      <div class="grid gap-2.75 p-4" aria-hidden="true">
        <span class="block h-2.5 w-[70%] rounded-full bg-thb15-line"></span>
        <span class="block h-2.5 w-[88%] rounded-full bg-thb15-line"></span>
        <span class="block h-2.5 w-[54%] rounded-full bg-thb15-line"></span>
      </div>
    </div>
    <p class="text-xs leading-relaxed text-thb15-mut text-pretty" aria-hidden="true">Real Tailwind, no shim &mdash; the CSS version of this demo had to hand-write these utilities to render. The card is narrower than <code class="font-thb15-mono text-[11px] px-1.5 py-0.5 rounded bg-thb15-line">@md</code>, so you see the mobile state; the docs give the <code class="font-thb15-mono text-[11px] px-1.5 py-0.5 rounded bg-thb15-line">peer-checked</code> no-JS variant.</p>
  </div>
</section>
@import "tailwindcss";

@theme {
  --color-thb15-bg: #fafafa;
  --color-thb15-bg: oklch(0.985 0 0);
  --color-thb15-edge: #e4e4e7;
  --color-thb15-edge: oklch(0.92 0.004 286);
  --color-thb15-line: #ededf0;
  --color-thb15-line: oklch(0.94 0.002 286);
  --color-thb15-hover: #f4f4f5;
  --color-thb15-hover: oklch(0.96 0.002 286);
  --color-thb15-ink: #27272a;
  --color-thb15-ink: oklch(0.21 0.006 286);
  --color-thb15-mut: #71717a;
  --color-thb15-mut: oklch(0.55 0.014 286);
  --color-thb15-acc: #2f7fd4;
  --color-thb15-acc: oklch(0.59 0.16 245);
  --font-thb15-sans: 'Space Grotesk', system-ui, sans-serif;
  --font-thb15-mono: 'JetBrains Mono', ui-monospace, monospace;
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's
   w-full min-h-svh. It scopes the demo, and it holds the stage at full height in the
   moment before the browser build has compiled its utilities. */

.thb-15 {
  width: 100%;
  min-height: 100svh;
}
(function () {
  document.querySelectorAll('.thb-15 .thb15-burger').forEach(function (btn) {
    if (btn.dataset.bound) return; btn.dataset.bound = '1';
    var menu = document.getElementById('thb15-menu');
    btn.addEventListener('click', function () {
      var open = menu.classList.toggle('hidden') === false;
      btn.setAttribute('aria-expanded', String(open));
      btn.setAttribute('aria-label', open ? 'Close menu' : 'Open menu');
      btn.querySelector('.thb15-open').classList.toggle('hidden', open);
      btn.querySelector('.thb15-close').classList.toggle('hidden', !open);
    });
  });
})();

Setup — do this once per project

Skip this if your project already runs Tailwind v4.

1Load Tailwind
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>

Compiles in the browser — perfect for a CodePen or a quick test, not for production.

2Add the stylesheetRequiredthe @theme block is what makes the custom utilities exist
@import "tailwindcss";

@theme {
  --color-thb15-bg: #fafafa;
  --color-thb15-bg: oklch(0.985 0 0);
  --color-thb15-edge: #e4e4e7;
  --color-thb15-edge: oklch(0.92 0.004 286);
  --color-thb15-line: #ededf0;
  --color-thb15-line: oklch(0.94 0.002 286);
  --color-thb15-hover: #f4f4f5;
  --color-thb15-hover: oklch(0.96 0.002 286);
  --color-thb15-ink: #27272a;
  --color-thb15-ink: oklch(0.21 0.006 286);
  --color-thb15-mut: #71717a;
  --color-thb15-mut: oklch(0.55 0.014 286);
  --color-thb15-acc: #2f7fd4;
  --color-thb15-acc: oklch(0.59 0.16 245);
  --font-thb15-sans: 'Space Grotesk', system-ui, sans-serif;
  --font-thb15-mono: 'JetBrains Mono', ui-monospace, monospace;
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's
   w-full min-h-svh. It scopes the demo, and it holds the stage at full height in the
   moment before the browser build has compiled its utilities. */

.thb-15 {
  width: 100%;
  min-height: 100svh;
}
3Fonts used by this demooptional — skip if you have your own type stack
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap">

What changed in the port

Which parts became utilities, which stayed CSS, and why.

  • The only demo in the collection that did not need porting — and the one that gained the most. The CSS version shipped a 40-line shim of hand-written [class~=&quot;md:flex&quot;] rules just to render; here the real compiler runs and the shim is gone.
  • Breakpoint variants become container variants (@md: on an @container wrapper) so the demo responds to the card rather than the browser window — the same substitution any embedded navbar should make.
  • The two-SVG icon swap keeps [grid-area:1/1] as an arbitrary property, since overlaying grid children is not a design-scale value.
  • aria-current: replaces the [aria-current=&quot;page&quot;] rules on both link lists, so the active state cannot drift from the markup.
  • Focus rings are stated per element rather than in one shared rule. More typing, but a copy-pasted button carries its own focus state — which is exactly the failure mode this demo exists to prevent.
  • The three-line script is unchanged from the CSS version, including the === false inversion. Tailwind changes styling, not the truthfulness of ARIA.
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 demo 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: Tailwind CSS Responsive Hamburger Menu Component
Source: https://codefronts.com/navigation/tailwind-hamburger-menus/tailwind-css-responsive-hamburger-menu-component/

The canonical Tailwind navbar &mdash; and in this collection it is the one demo that needed no port at all, because the original was already written in utilities. What it gains here is honesty: the CSS version had to ship a hand-written shim to render those classes, and this one runs the real compiler, so what you see is exactly what hidden md:flex produces.
## HTML
```html
<section class="thb-15 w-full min-h-svh bg-thb15-bg font-thb15-sans text-thb15-ink px-5 py-9" aria-label="Tailwind CSS hamburger menu demo">
  <div class="grid gap-3.5 p-5 rounded-[18px] border border-thb15-edge bg-thb15-bg">
    <div class="@container overflow-hidden rounded-[14px] border border-thb15-edge bg-white shadow-[0_14px_34px_-26px_oklch(0.3_0.02_286/0.6)]">
      <nav class="flex items-center justify-between px-4 py-3 bg-white border-b border-thb15-edge" aria-label="Primary">
        <a href="#home" class="flex items-center gap-2 font-bold text-thb15-ink no-underline">
          <span class="w-4.5 h-4.5 rounded-md bg-[conic-gradient(from_200deg,var(--color-thb15-acc),oklch(0.72_0.14_190))]" aria-hidden="true"></span>tailfleet
        </a>
        <div class="hidden @md:flex @md:items-center @md:gap-1">
          <a href="#features" aria-current="page" class="inline-flex items-center min-h-9.5 px-3 rounded-[9px] text-[13.5px] font-semibold text-thb15-mut no-underline transition-[color,background] duration-150 hover:text-thb15-ink hover:bg-thb15-hover focus-visible:outline-2 focus-visible:outline-thb15-acc focus-visible:outline-offset-2 aria-current:text-thb15-acc">Features</a>
          <a href="#pricing" class="inline-flex items-center min-h-9.5 px-3 rounded-[9px] text-[13.5px] font-semibold text-thb15-mut no-underline transition-[color,background] duration-150 hover:text-thb15-ink hover:bg-thb15-hover focus-visible:outline-2 focus-visible:outline-thb15-acc focus-visible:outline-offset-2">Pricing</a>
          <a href="#docs" class="inline-flex items-center min-h-9.5 px-3 rounded-[9px] text-[13.5px] font-semibold text-thb15-mut no-underline transition-[color,background] duration-150 hover:text-thb15-ink hover:bg-thb15-hover focus-visible:outline-2 focus-visible:outline-thb15-acc focus-visible:outline-offset-2">Docs</a>
          <a href="#blog" class="inline-flex items-center min-h-9.5 px-3 rounded-[9px] text-[13.5px] font-semibold text-thb15-mut no-underline transition-[color,background] duration-150 hover:text-thb15-ink hover:bg-thb15-hover focus-visible:outline-2 focus-visible:outline-thb15-acc focus-visible:outline-offset-2">Blog</a>
        </div>
        <div class="flex items-center gap-2">
          <a href="#signup" class="hidden @md:inline-flex items-center min-h-10 px-4 rounded-[10px] bg-thb15-ink text-white text-[13px] font-bold no-underline transition-[background] duration-200 hover:bg-thb15-acc focus-visible:outline-2 focus-visible:outline-thb15-acc focus-visible:outline-offset-2">Sign up</a>
          <button type="button" aria-expanded="false" aria-controls="thb15-menu" aria-label="Open menu" class="thb15-burger grid place-items-center w-11 h-11 rounded-[10px] border border-thb15-edge bg-white text-thb15-ink cursor-pointer transition-[background] duration-150 hover:bg-thb15-hover focus-visible:outline-2 focus-visible:outline-thb15-acc focus-visible:outline-offset-2 @md:hidden">
            <svg class="thb15-open [grid-area:1/1]" viewBox="0 0 24 24" width="22" height="22" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><path d="M4 6h16M4 12h16M4 18h16"/></svg>
            <svg class="thb15-close hidden [grid-area:1/1]" viewBox="0 0 24 24" width="22" height="22" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><path d="m6 6 12 12M18 6 6 18"/></svg>
          </button>
        </div>
      </nav>
      <div id="thb15-menu" class="hidden px-3 pb-3 bg-white border-b border-thb15-edge @md:hidden">
        <a href="#features" aria-current="page" class="flex items-center min-h-11 px-3 rounded-[9px] text-sm font-semibold text-thb15-mut no-underline transition-[background,color] duration-150 hover:bg-thb15-hover hover:text-thb15-ink focus-visible:outline-2 focus-visible:outline-thb15-acc focus-visible:-outline-offset-2 aria-current:text-thb15-acc">Features</a>
        <a href="#pricing" class="flex items-center min-h-11 px-3 rounded-[9px] text-sm font-semibold text-thb15-mut no-underline transition-[background,color] duration-150 hover:bg-thb15-hover hover:text-thb15-ink focus-visible:outline-2 focus-visible:outline-thb15-acc focus-visible:-outline-offset-2">Pricing</a>
        <a href="#docs" class="flex items-center min-h-11 px-3 rounded-[9px] text-sm font-semibold text-thb15-mut no-underline transition-[background,color] duration-150 hover:bg-thb15-hover hover:text-thb15-ink focus-visible:outline-2 focus-visible:outline-thb15-acc focus-visible:-outline-offset-2">Docs</a>
        <a href="#blog" class="flex items-center min-h-11 px-3 rounded-[9px] text-sm font-semibold text-thb15-mut no-underline transition-[background,color] duration-150 hover:bg-thb15-hover hover:text-thb15-ink focus-visible:outline-2 focus-visible:outline-thb15-acc focus-visible:-outline-offset-2">Blog</a>
        <a href="#signup" class="flex items-center justify-center w-full min-h-10 mt-2 px-4 rounded-[10px] bg-thb15-ink text-white text-[13px] font-bold no-underline transition-[background] duration-200 hover:bg-thb15-acc focus-visible:outline-2 focus-visible:outline-thb15-acc focus-visible:outline-offset-2">Sign up</a>
      </div>
      <div class="grid gap-2.75 p-4" aria-hidden="true">
        <span class="block h-2.5 w-[70%] rounded-full bg-thb15-line"></span>
        <span class="block h-2.5 w-[88%] rounded-full bg-thb15-line"></span>
        <span class="block h-2.5 w-[54%] rounded-full bg-thb15-line"></span>
      </div>
    </div>
    <p class="text-xs leading-relaxed text-thb15-mut text-pretty" aria-hidden="true">Real Tailwind, no shim &mdash; the CSS version of this demo had to hand-write these utilities to render. The card is narrower than <code class="font-thb15-mono text-[11px] px-1.5 py-0.5 rounded bg-thb15-line">@md</code>, so you see the mobile state; the docs give the <code class="font-thb15-mono text-[11px] px-1.5 py-0.5 rounded bg-thb15-line">peer-checked</code> no-JS variant.</p>
  </div>
</section>
```
## CSS
```css
@import "tailwindcss";

@theme {
  --color-thb15-bg: #fafafa;
  --color-thb15-bg: oklch(0.985 0 0);
  --color-thb15-edge: #e4e4e7;
  --color-thb15-edge: oklch(0.92 0.004 286);
  --color-thb15-line: #ededf0;
  --color-thb15-line: oklch(0.94 0.002 286);
  --color-thb15-hover: #f4f4f5;
  --color-thb15-hover: oklch(0.96 0.002 286);
  --color-thb15-ink: #27272a;
  --color-thb15-ink: oklch(0.21 0.006 286);
  --color-thb15-mut: #71717a;
  --color-thb15-mut: oklch(0.55 0.014 286);
  --color-thb15-acc: #2f7fd4;
  --color-thb15-acc: oklch(0.59 0.16 245);
  --font-thb15-sans: 'Space Grotesk', system-ui, sans-serif;
  --font-thb15-mono: 'JetBrains Mono', ui-monospace, monospace;
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's
   w-full min-h-svh. It scopes the demo, and it holds the stage at full height in the
   moment before the browser build has compiled its utilities. */

.thb-15 {
  width: 100%;
  min-height: 100svh;
}
```

## JavaScript
```js
(function () {
  document.querySelectorAll('.thb-15 .thb15-burger').forEach(function (btn) {
    if (btn.dataset.bound) return; btn.dataset.bound = '1';
    var menu = document.getElementById('thb15-menu');
    btn.addEventListener('click', function () {
      var open = menu.classList.toggle('hidden') === false;
      btn.setAttribute('aria-expanded', String(open));
      btn.setAttribute('aria-label', open ? 'Close menu' : 'Open menu');
      btn.querySelector('.thb15-open').classList.toggle('hidden', open);
      btn.querySelector('.thb15-close').classList.toggle('hidden', !open);
    });
  });
})();
```

How this works

Four utility decisions on three elements.

<nav class="flex items-center justify-between …">
  <div class="hidden md:flex md:items-center md:gap-1">…links…</div>
  <button class="md:hidden" aria-expanded="false">burger</button>
</nav>
<div id="menu" class="hidden md:hidden …">…mobile links…</div>

hidden md:flex reads as: display:none by default (mobile), display:flex from the md breakpoint. The burger is the mirror image. The panel starts hidden AND stays md:hidden, which is the one extra utility that prevents the resize bug demo 13 also calls out.

The whole script is three lines, and the inversion matters:

const open = menu.classList.toggle('hidden') === false;
btn.setAttribute('aria-expanded', String(open));

classList.toggle returns the NEW presence of the class, so hidden removed means the menu is open. Copying this without the === false ships an aria-expanded that lies.

Zero-JS variant. Make the toggle a peer checkbox and the panel hidden peer-checked:grid md:hidden. Same checkbox-hack trade-offs as demo 05 — which is why the JS version is the primary recipe here: it keeps aria-expanded truthful.

Why hidden and not invisible. hidden is display:none, which removes the panel from the accessibility tree. invisible or opacity-0 leave every link Tab-reachable behind an invisible panel.

Make it yours

  • Breakpoint: swap every md: for lg: to hold the burger until 1024px. Crowded navs break later, not never.
  • For an embedded navbar (docs shell, admin, Storybook) swap the breakpoint variants for @container + @md: as in demo 13 — the component then measures itself.
  • The icon swap is two overlaid SVGs toggled with hidden. Port demo 03's three-span icon in if you want motion.
  • Dark mode is native: prefix the surface utilities (dark:bg-zinc-900 dark:text-zinc-100) and the component follows your dark strategy.
  • For the no-JS variant the checkbox needs peer sr-only — sr-only keeps it focusable, and hidden would not.

Gotchas — read before shipping

  • classList.toggle returns the class's NEW presence. The === false inversion is deliberate; without it aria-expanded is inverted and screen readers announce the opposite of reality.
  • Never swap hidden for invisible or opacity-0 on the panel. Both leave the links keyboard-focusable while invisible.
  • transition-all will not animate the panel open: height:auto is not transitionable. Use the grid-rows recipe from demo 18, or accept the instant toggle.
  • peer-checked: requires the peer input to be a preceding SIBLING of the panel. Tailwind does not lift that DOM constraint — has-checked: (demo 09) does.
  • Utilities are only generated for class strings the compiler can see. A panel class assembled at runtime produces no CSS — toggle a static class like hidden instead.
  • The browser CDN build compiles in the page. Ship the CLI or a plugin build, or the first paint carries an unstyled flash.

Browser support

ChromeSafariFirefoxEdge
111+16.4+128+111+

The utilities compile to plain flex and display rules that run anywhere; the floor is Tailwind v4's own generated sheet (cascade layers, @property, color-mix()). The container-query alternative needs Chrome 105, Safari 16 and Firefox 110.

Techniques used in this demo

Theme tokensset in @theme, used by a utility

Search CodeFronts

Loading…