Home / Snippets / UI Components /

Hamburger menu

Three-bar icon that morphs into an X on click using a hidden checkbox and CSS transforms.

Click to toggle
Widely Supported
uino-js

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.