Home / Snippets / UI Components /
Hamburger menu
Three-bar icon that morphs into an X on click using a hidden checkbox and CSS transforms.
Quick implementation
/* HTML:
<input type="checkbox" id="ham" class="hamburger-input" />
<label for="ham" class="hamburger-btn" aria-label="Toggle menu">
<span class="hamburger-bar"></span>
<span class="hamburger-bar"></span>
<span class="hamburger-bar"></span>
</label>
*/
.hamburger-input { display: none; }
.hamburger-btn {
display: flex;
flex-direction: column;
justify-content: center;
gap: 5px;
width: 2.75rem;
height: 2.75rem;
padding: 0.5rem;
border: 1px solid oklch(0.3 0.02 260);
border-radius: 0.5rem;
background: oklch(0.19 0.02 260);
cursor: pointer;
}
.hamburger-bar {
display: block;
width: 100%;
height: 2px;
background: oklch(0.93 0.01 260);
border-radius: 1px;
transition: transform 0.3s ease, opacity 0.3s ease;
}
.hamburger-input:checked + .hamburger-btn .hamburger-bar:nth-child(1) {
transform: translateY(7px) rotate(45deg);
}
.hamburger-input:checked + .hamburger-btn .hamburger-bar:nth-child(2) {
opacity: 0;
}
.hamburger-input:checked + .hamburger-btn .hamburger-bar:nth-child(3) {
transform: translateY(-7px) rotate(-45deg);
}
@media (prefers-reduced-motion: reduce) {
.hamburger-bar { transition: none; }
}
Prompt this to your LLM
Includes role, constraints, two framework variants, and edge cases to handle.
You are a senior frontend engineer building responsive navigation.
Goal: A hamburger icon that morphs into an X on toggle using CSS transforms — no JavaScript for the animation.
Technical constraints:
- Use a hidden checkbox + label pattern for the CSS-only toggle.
- Three span bars inside the label — the middle fades, top/bottom rotate ±45deg.
- translateY offset must match the gap + bar height to converge at center.
- Transition transform and opacity at 0.3s ease.
- Use oklch() for all color values, not hex or rgba().
- Touch target must be at least 44×44px (WCAG 2.5.8).
- Wrap transitions in @media (prefers-reduced-motion: reduce).
Framework variant (pick one):
A) Vanilla HTML + CSS only.
B) React component — accept isOpen (boolean), onToggle handler, and ariaLabel (string) props.
Edge cases to handle:
- Keyboard access: the label must be focusable (it is, as it targets a form control).
- Screen readers: use aria-label="Toggle menu" on the label.
- In production, pair with a JS handler to also toggle aria-expanded on the button.
- RTL: hamburger is symmetric, no changes needed.
Return HTML + CSS.
Why this matters in 2026
The hamburger icon is ubiquitous in mobile navigation. JavaScript-based toggle animations add bundle weight and often cause a flash of unstyled content during hydration. The CSS-only :checked approach animates instantly on page load — no JS dependency, no hydration delay. In production you'll add a small JS handler for aria-expanded, but the visual animation is pure CSS.
The logic
Three <span> bars are stacked with a 5px gap inside a flex-direction: column label. When the hidden checkbox is :checked, the first bar translates down and rotates 45°, the last translates up and rotates −45°, and the middle bar fades to opacity: 0. The translateY value (7px) equals the gap (5px) plus the bar height (2px), so the two bars converge exactly at the center to form a perfect X.
Accessibility & performance
The <label> linked to a checkbox is natively focusable and activatable with Enter/Space. Add aria-label="Toggle menu" so screen readers announce the purpose. In production, also toggle aria-expanded="true/false" on the element via JavaScript. The animations use only transform and opacity — both compositor-friendly properties that don't trigger layout or paint.