Stagger Menu Reveal
Adding .revealed slides each menu item from the left with a 50 ms progressive delay — spring cubic-bezier, zero animation loop.
You'll get access to the interactive demo with a free account.
This effect is part of Effect.Labs — 811 vanilla effects, some free, some premium. Navigation has 36 effects, including 4 free. Explore the category →
3 usage examples



How it works
The effect is entirely CSS-driven. Each .stagger-menu-item starts at opacity: 0 and transform: translateX(-20px). Adding the class .revealed to the parent container triggers the transition to opacity: 1 and translateX(0) for all items simultaneously in a single DOM operation.
The time offset (stagger) is produced by :nth-child rules: first item at 0 s, second at 50 ms, third at 100 ms, fourth at 150 ms. Each item waits for its delay before running its own 400 ms transition — the visual cascade is entirely CSS-driven, with no JavaScript scheduler.
The curve cubic-bezier(.34, 1.56, .64, 1) is a spring curve: it slightly overshoots the target value before settling, producing a characteristic elastic snap. This overshoot is more expressive than a plain ease-out for UI elements and reinforces the feeling of responsiveness.
JavaScript is limited to listening for mouseenter and mouseleave on the parent to toggle .revealed, plus a setTimeout(500 ms) that automatically reveals items on load. No requestAnimationFrame, no animation loop.
Accessibility
- prefers-reduced-motion absent: the code contains no
prefers-reduced-motionhandling — animations fire regardless of OS preference. Recommended fix: wrap thetransitionrule in.stagger-menu-iteminside a@media (prefers-reduced-motion: no-preference)block. - Items are
<span>elements — not keyboard-focusable by default. For real navigation, replace with<a>tags or addtabindex="0"+ akeydownhandler (Enter / Space). - The trigger is
mouseenteronly — not accessible on touchscreens or via keyboard. ThesetTimeout(500 ms)auto-reveal on load mitigates the display issue but does not provide keyboard interaction. - No ARIA role or
aria-labelon the container. For accessible navigation: addrole="navigation"and a descriptivearia-labelon the.stagger-menu. - Color contrast: default text
#a1a1aaon#0a0a0f≈ 8:1 — passes WCAG AA ✓; hover text#6366f1≈ 4.5:1 — passes WCAG AA (borderline) ✓.
Browser compatibility
Relies solely on CSS transitions and :nth-child selectors — zero external dependencies, supported in all modern browsers since 2015.
Without CSS transition support (IE 9 and below), items render statically at their final position — no JS errors, navigation remains fully functional.
The code
HTML structure to paste into your page (CSS + JS available with a premium account):
<div class="stagger-menu" id="staggerMenu">
<span class="stagger-menu-item">Item 1</span>
<span class="stagger-menu-item">Item 2</span>
<span class="stagger-menu-item">Item 3</span>
<span class="stagger-menu-item">Item 4</span>
</div>
Full HTML + CSS + JS, copy-paste ready — with hundreds of premium effects.
Customize
Options passed to the API or data-* attributes:
| Option / property | Default | Effect |
|---|---|---|
| transition-delay (nth-child) | 0 / 50 / 100 / 150 ms | Per-item delay in :nth-child rules — increase the step (e.g. 80 ms) for a slower stagger, reduce (30 ms) for a snappier feel. Add one rule per additional item beyond 4. |
| transition duration (.4s) | 400 ms | Duration of each individual transition in .stagger-menu-item. Shorten to 250 ms for a fast dropdown, extend to 600 ms for a cinematic effect. |
| cubic-bezier(.34, 1.56, .64, 1) | spring / bounce | Spring curve with overshoot. Replace with cubic-bezier(0, 0, 0.2, 1) for smooth ease-out without bounce, or (.68, -0.55, .27, 1.55) for stronger overshoot. |
| translateX(-20px) | -20px | Entry distance and direction in .stagger-menu-item. translateX(20px) reverses direction (right to left), translateY(10px) gives a vertical downward entry. |
| --text-secondary (#a1a1aa) | #a1a1aa | Item color at rest — modify the :root CSS variable to adapt the whole theme without touching individual rules. |
| hover background (rgba(99,102,241,.1)) | indigo 10% | Hover background in .stagger-menu-item:hover — replace with your brand color rgba (e.g. rgba(16,185,129,.1) for emerald green). |
| hover color (#6366f1) | #6366f1 (indigo) | Hover text color in .stagger-menu-item:hover — ensure ≥ 4.5:1 contrast ratio on the dark background after changing. |
| setTimeout delay (500 ms) | 500 ms | Delay before auto-reveal on load in the JS. Reduce to 200 ms for near-immediate appearance, increase to 1000 ms for a deliberate delayed reveal. |
FAQ
<span class="stagger-menu-item"> elements as needed in the HTML, then add a CSS rule .stagger-menu.revealed .stagger-menu-item:nth-child(N) { transition-delay: Nx0.05s } for each additional item — for example item 5 → 0.20s, item 6 → 0.25s.document.getElementById('staggerMenu').classList.add('revealed') to reveal, .classList.remove('revealed') to hide. Wire it to any event: modal open, load complete, route transition, API response..revealed plays the transition in reverse through the same CSS rules: items slide back left and fade out, last item first (delays naturally invert on hide). No extra code needed.