Skip to content

feat: ease-dropdown — Animated CSS-only dropdown menu component#878

Open
AjayBandiwaddar wants to merge 5 commits into
SAPTARSHI-coder:mainfrom
AjayBandiwaddar:feat/ease-dropdown
Open

feat: ease-dropdown — Animated CSS-only dropdown menu component#878
AjayBandiwaddar wants to merge 5 commits into
SAPTARSHI-coder:mainfrom
AjayBandiwaddar:feat/ease-dropdown

Conversation

@AjayBandiwaddar
Copy link
Copy Markdown

@AjayBandiwaddar AjayBandiwaddar commented Jun 2, 2026

Pull Request Description

Adds ease-dropdown — a fully CSS-only animated floating dropdown menu component. Opens via :focus-within (zero JavaScript), closes automatically when focus leaves the trigger, and composes directly with existing ease-btn variants. Fills the navigation component gap explicitly listed as Planned v1.3 in VISION.md.


Type of Change

  • 🧩 New component

Submission Checklist

⚠️ PRs that fail this checklist will be closed without review.

  • All changes are inside submissions/examples/ease-dropdown/
  • Includes demo.html — self-contained, opens in browser with no server
  • Includes style.css — raw CSS for the proposed feature
  • Includes README.md — what it does, how to use it, why it fits EaseMotion CSS
  • No changes to core/
  • No changes to components/
  • One feature per PR (no bundled unrelated changes)

Feature Description

What does this add?

A floating dropdown menu component with a smooth top-down entrance animation, four layout variants, and full keyboard/screen-reader accessibility — no JavaScript required.

How does a developer use it?

<!-- Basic dropdown -->
<div class="dropdown">
  <button class="ease-btn ease-btn-primary dropdown-trigger"
          aria-haspopup="menu" type="button">
    Options
    <span class="dropdown-chevron" aria-hidden="true"></span>
  </button>

  <ul class="dropdown-menu" role="menu">
    <li role="none"><a class="dropdown-item" href="#" role="menuitem" tabindex="-1">Edit</a></li>
    <li role="none"><a class="dropdown-item" href="#" role="menuitem" tabindex="-1">Duplicate</a></li>
    <li class="dropdown-divider" role="separator"></li>
    <li role="none"><a class="dropdown-item dropdown-item-danger" href="#" role="menuitem" tabindex="-1">Delete</a></li>
  </ul>
</div>

<!-- Position modifiers -->
<div class="dropdown dropdown--right"></div>   <!-- panel anchors to right edge -->
<div class="dropdown dropdown--up"></div>   <!-- panel opens upward -->
<div class="dropdown dropdown--wide"></div>   <!-- 240px min-width panel -->

Why does it fit EaseMotion CSS?

  • Human-readable class names.dropdown, .dropdown-trigger, .dropdown-menu, .dropdown-item-danger read exactly like what they do, matching the framework's core philosophy.
  • Animation-first — the entrance uses opacity 0→1 + scaleY(0.94)→1 with transform-origin: top center, the same motion language as ease-slide-down and ease-card-hover. The .dropdown--up modifier correctly flips transform-origin to bottom center.
  • Token-driven — all 55 var(--ease-*) references carry raw fallback literals, so the component works standalone and also immediately adopts any future theme changes to core/variables.css.
  • Composable — the trigger is style-agnostic; it works with .ease-btn-primary, .ease-btn-ghost, .ease-btn-outline, or any custom element.
  • Zero dependencies — open/close state is driven entirely by :focus-within. The browser manages focus, so clicking outside dismisses the panel with no event listeners.
  • Roadmap-aligned — VISION.md lists "Navigation components (navbar, sidebar)" as Planned v1.3. A dropdown is the atomic primitive every navigation pattern builds on.

Demo

  • Demo added (demo.html works by opening directly in a browser)

The demo shows four variants:

  1. Navigation menu — three trigger styles (primary, ghost, outline) each with a linked panel
  2. Action menu — section labels, muted/disabled item, and a destructive danger item
  3. Position modifiers — right-aligned panel and upward-opening panel side by side
  4. Icon-only trigger — three-dot context menu using aria-label instead of visible text

Browser Testing

  • Chrome
  • Edge

Notes for Maintainer

Naming: Class names are intentionally left without the ease- prefix on internals (.dropdown-menu, .dropdown-item) so you can standardize them however fits the framework best — e.g. ease-dropdown-menu, ease-menu, etc.

Accessibility choices worth knowing:

  • aria-haspopup="menu" is on the trigger; aria-expanded is intentionally omitted since it can't be toggled without JS and a hardcoded false would be misleading.
  • role="none" on <li> elements removes the implicit list semantics so role="menuitem" on the <a> is the sole announced role — the correct pattern per WAI-ARIA 1.2.
  • tabindex="-1" on items prevents a double tab stop; the trigger opens the panel and Tab walks through items naturally.

The chevron is a CSS mask-image inline SVG rather than a Unicode character — it inherits currentColor, scales with font-size, and renders consistently across OSes without font-metric quirks.

prefers-reduced-motion sets transition-duration: 1ms on animated elements, matching the pattern used in ease-accordion.

Feel free to adjust any timing values or rename classes during integration — happy to update the submission if anything needs changing before merge.

@AjayBandiwaddar AjayBandiwaddar changed the title feat: /ease dropdown feat: ease-dropdown — Animated CSS-only dropdown menu component Jun 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant