15 / 28
All 28 in 28 Tailwind Hamburger Menus
- 01Tailwind Hamburger Menu with Clip-Path Circle Expansion
- 02Tailwind Keyboard Navigable Hamburger Menu with ARIA Attributes
- 03Tailwind Animated 3-Line to X Hamburger Icon Toggle
- 04Tailwind Slide-In Off-Canvas Drawer with Dimmed Backdrop Overlay
- 05Pure Tailwind Checkbox Hack Hamburger Navigation (No JavaScript)
- 06Tailwind Responsive Hamburger Menu with Integrated Search Bar & Social Links
- 07Tailwind Glassmorphism Backdrop Blur Hamburger Navigation
- 08Tailwind Push Page Navigation Menu (Off-Canvas Content Shift)
- 09Pure Tailwind Hamburger Menu Without JavaScript
- 10Tailwind Hamburger Menu Morphing to Close Icon Animation
- 11Tailwind Full Screen Mobile Navigation Overlay
- 12Tailwind Slide Out Sidebar Navigation / Off Canvas Menu
- 13Tailwind Responsive Navbar Mobile Hamburger Toggle Breakpoints
- 14Tailwind Minimalist Floating Hamburger Button
- 15Tailwind CSS Responsive Hamburger Menu Component
- 16Tailwind Rebuild of the Bootstrap 5 Navbar Hamburger Toggle
- 17Tailwind WCAG Accessible Hamburger Menu Example
- 18Pure Tailwind Dropdown Slide Down Mobile Hamburger Menu
- 19Simple 3-Line Tailwind Hamburger Icon Hover Effect
- 20Tailwind Full Screen Blur Overlay Hamburger Menu
- 21Tailwind Mobile Bottom Navigation Bar with Floating Hamburger Toggle
- 22Pure Tailwind Multi-Level Accordion Hamburger Dropdown Menu
- 23Flexbox Navbar Right-Aligned Tailwind Hamburger Icon
- 24Radial Ripple Expand Tailwind Hamburger Menu
- 25Sticky Tailwind Navbar Shrinking Hamburger Icon on Scroll
- 26Neumorphic Tailwind Hamburger Toggle Button
- 27Brutalist Design Bordered Tailwind Hamburger Menu
- 28Tailwind 3D Flip Canvas Mobile Hamburger Navigation
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.
Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time
Untitled UI React · Affiliate link
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 — 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><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 — 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;
}@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);
});
});
})();(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.
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<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.
npm install tailwindcss @tailwindcss/vite
npm install tailwindcss @tailwindcss/vite// vite.config.js ("type": "module" in package.json)
import { defineConfig } from 'vite'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [tailwindcss()],
})// vite.config.js ("type": "module" in package.json)
import { defineConfig } from 'vite'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [tailwindcss()],
})Any v4 setup works — Vite, PostCSS or the CLI. Nothing in this demo is bundler-specific.
@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;
}@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;
}<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">
<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~="md:flex"]rules just to render; here the real compiler runs and the shim is gone. - Breakpoint variants become container variants (
@md:on an@containerwrapper) 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="page"]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
=== falseinversion. Tailwind changes styling, not the truthfulness of ARIA.
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 — 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 — 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);
});
});
})();
```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 — 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 — 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:forlg: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 yourdarkstrategy. - For the no-JS variant the checkbox needs
peer sr-only—sr-onlykeeps it focusable, andhiddenwould not.
Gotchas — read before shipping
classList.togglereturns the class's NEW presence. The=== falseinversion is deliberate; without itaria-expandedis inverted and screen readers announce the opposite of reality.- Never swap
hiddenforinvisibleoropacity-0on the panel. Both leave the links keyboard-focusable while invisible. transition-allwill not animate the panel open:height:autois not transitionable. Use thegrid-rowsrecipe 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
hiddeninstead. - 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
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 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.