Navigation✨ Premium

Dropdown Animated

Animated dropdown menu with a CSS stagger reveal: each item slides in from the left with a 50 ms delay — single class toggle, no dependencies.

CSSJSStagger

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

SaaS header — User account menu — Dropdown Animated example 1

① SaaS header — User account menu

WhenIn a web application's navigation bar, when the user clicks their avatar or name to access profile, settings, or sign out.
WhyItems cascade in from the left in 200 ms total — immediate and fluid feedback without visually weighing down the rest of the interface; the menu closes on the first outside click.
Settings4 items (Profile, Settings, Help, Sign out), default delays (0.05 s / 0.10 s / 0.15 s / 0.20 s), hover rgba(99,102,241,.2) swapped for brand primary color.
Dashboard — View or quick-filter selector — Dropdown Animated example 2

② Dashboard — View or quick-filter selector

WhenIn an analytics or management interface, when the user switches display mode (List, Grid, Timeline) or applies a quick filter to a widget or table.
WhyThe 50 ms stagger draws the eye to available options without intrusive animation — items arrive cleanly, and the cascade visually signals there are multiple choices to scan.
Settings3 to 5 items, transition-delay of 0.05 s per step, panel background adjusted for the dark dashboard (background: rgba(18,18,30,.98)), min-width: 180px.
Agency / portfolio site — 8-item navigation menu in cascade — Dropdown Animated example 3

③ Agency / portfolio site — 8-item navigation menu in cascade

WhenOn an agency or portfolio site, when the user opens the main navigation menu to browse all available sections (Web Design, Branding, Motion, SEO, E-commerce, Apps, UX, Audit…) on click.
WhyWith 8 items spread across a large surface, the 50 ms stagger showcases the full depth of the offer: each section arrives in turn, guiding the eye and making the cascade unmissably visible — without making the menu feel slow to open.
Settings8 items, transition-delay of 0.05 s per step (last item at 0.40 s), min-width: 240px, panel background rgba(255,255,255,.98) with dark text — demonstrates the stagger works independently of the site's color theme.

How it works

Opening relies on a CSS class toggle: the JS function toggleDropdown() adds or removes the class active on the .anim-dropdown-container wrapper. No animation library is involved — all rendering is driven by the browser's native transition engine.

The .anim-dropdown-menu panel transitions simultaneously from opacity: 0 to 1, from visibility: hidden to visible, and from transform: translateY(-10px) to translateY(0) over 0.3 s. Using visibility (instead of display: none) preserves transition continuity while blocking clicks and focus when the menu is invisible.

The stagger effect is entirely declarative CSS: each .anim-dropdown-item starts at opacity: 0; transform: translateX(-10px) and transitions to opacity: 1; translateX(0). The :nth-child(1…4) rules assign transition-delay values of 0.05 s / 0.10 s / 0.15 s / 0.20 s respectively — the last item arrives 200 ms after opening begins. Adding more items only requires one extra :nth-child(N) rule.

Closing is triggered three ways: re-clicking the trigger button, clicking outside the container (a document click listener checks contains(e.target)), or pressing Escape. The chevron icon rotates 180° via transform: rotate(180deg) on .anim-dropdown-container.active .anim-dropdown-icon.

Accessibility

  • prefers-reduced-motion not handled: the code contains no matchMedia('(prefers-reduced-motion: reduce)') check — CSS transitions run regardless of OS settings. Add @media (prefers-reduced-motion: reduce) { .anim-dropdown-menu, .anim-dropdown-item { transition: none } } manually for motion-sensitive users.
  • The trigger is a native <button>: keyboard activation (Enter / Space) works without extra code. The Escape key closes the menu (handled in JS via a keydown listener).
  • aria-expanded and aria-haspopup are missing from the provided code: add them manually on the <button> (aria-expanded="false" toggled to "true" on open, aria-haspopup="menu") so screen readers announce the menu state.
  • Menu items are non-focusable <div> elements: they are not reachable via Tab or arrow keys. For full keyboard navigation, replace them with <button> or <a> elements.
  • Contrast: rgba(255,255,255,.7) text on rgba(30,30,45,.98) background — ratio exceeds 4.5:1 WCAG AA. The indigo hover (rgba(99,102,241,.2)) does not degrade the white text.

Browser compatibility

Uses only CSS Transitions and classList — available in all modern browsers without vendor prefixes. Zero external dependencies.

Chrome 90+✓ Full
Firefox 90+✓ Full
Safari 14+✓ Full
Edge 90+✓ Full
Mobile iOS 14+✓ Touch OK
Android Chrome✓ Full

Without JS, the button is visible but the menu won't open. A pure-HTML fallback is possible by replacing the container with a native <code>&lt;details&gt;</code>/<code>&lt;summary&gt;</code> element — no animation, but fully functional without script.

The code

HTML structure to paste into your page (CSS + JS available with a premium account):

index.html — structure
<div class="anim-dropdown-container" id="dropdown">
  <button class="anim-dropdown-trigger" onclick="toggleDropdown()">
    Label
    <svg class="anim-dropdown-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
      <path d="M6 9l6 6 6-6"></path>
    </svg>
  </button>
  <div class="anim-dropdown-menu">
    <div class="anim-dropdown-item">
      <svg class="anim-dropdown-item-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">…</svg>
      Item 1
    </div>
    <!-- For each extra item, add to CSS:
         .anim-dropdown-container.active .anim-dropdown-item:nth-child(N) { transition-delay: Xs } -->
  </div>
</div>
🔒 Unlock the full code — from €2.99 the first month

Full HTML + CSS + JS, copy-paste ready — with hundreds of premium effects.

Customize

Options passed to the API or data-* attributes:

Option / propertyDefaultEffect
transition-delay :nth-child(N) 0.05 s per item Stagger delay per item — CSS rules .active .anim-dropdown-item:nth-child(1…4). Increase to 0.08 s for a more pronounced stagger, reduce to 0.02 s for near-simultaneous reveal.
transition: opacity .3s … (panel) 0.3 s Opening duration of the whole panel — 0.2 s for a snappy feel, 0.45 s for a softer render.
transform: translateY(-10px) (panel) -10px Vertical offset of the panel when closed. Increase to -20 px for a more pronounced drop, or swap for scaleY(0.92) for a fold-open effect.
transform: translateX(-10px) (items) -10px Horizontal offset of each item before reveal. Replace with translateY(8px) for a bottom-up entrance.
.anim-dropdown-item:hover background rgba(99,102,241,.2) Item hover color (indigo by default) — swap for your interface's primary tint.
min-width on .anim-dropdown-menu 200px Panel minimum width — increase to 260 px for long labels or a two-column layout.
Additional items 4 items For each extra item, declare .anim-dropdown-container.active .anim-dropdown-item:nth-child(N) { transition-delay: Xs } with Xs = 0.05 × N.

FAQ

The provided code uses getElementById('dropdown') and a global toggleDropdown() function — one instance per page. For multiple menus, update the function to accept an id: function toggleDropdown(id) { document.getElementById(id).classList.toggle('active'); }, then call onclick="toggleDropdown('menu-1')" on each trigger with its matching id.
Yes — the code is pure vanilla JS. In React, manage isOpen via useState and set className conditionally. In Vue, use :class="{ active: isOpen }" on the container. In Svelte, class:active={isOpen} is enough. The CSS stagger stays unchanged — only the class management differs.
CSS transitions automatically reverse when active is removed. For a different close (e.g. fast fade without slide), temporarily add a closing class via JS before removing active and define .closing .anim-dropdown-menu { transition: opacity .15s; } — then remove closing after the delay with setTimeout.