npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@magic-spells/dropdown-panel

v1.0.0

Published

Accessible custom dropdown panel web component.

Downloads

22

Readme

@magic-spells/dropdown-panel

A lightweight, accessible dropdown panel web component designed for modern web applications.

🔍 Live Demo - See it in action!

Features

  • 🪶 Lightweight and dependency-free (under 1KB CSS)
  • 🎨 Minimal styling - easy to integrate with any design system
  • 🔗 Supports nested dropdowns with opens="right" attribute
  • ⌨️ Full keyboard navigation with progressive menu closure
  • ♿ Accessible - follows ARIA best practices
  • 📱 Mobile-friendly

Installation

npm install @magic-spells/dropdown-panel

Usage

Import the component in your JavaScript:

// ESM import
import '@magic-spells/dropdown-panel';

// Or in HTML
<script src="node_modules/@magic-spells/dropdown-panel/dist/dropdown-panel.min.js"></script>
<link rel="stylesheet" href="node_modules/@magic-spells/dropdown-panel/dist/dropdown-panel.min.css">

Then use it in your HTML:

<dropdown-component>
  <dropdown-trigger>Menu</dropdown-trigger>
  <dropdown-panel>
    <a href="#" class="dropdown-item">Option 1</a>
    <a href="#" class="dropdown-item">Option 2</a>
    <div class="dropdown-divider"></div>
    <a href="#" class="dropdown-item">Option 3</a>
  </dropdown-panel>
</dropdown-component>

For a larger "mega menu" style layout, add the wide attribute to <dropdown-panel>:

<dropdown-component>
  <dropdown-trigger>Products</dropdown-trigger>
  <dropdown-panel wide>
    <div>
      <a href="#" class="dropdown-item">Software</a>
      <a href="#" class="dropdown-item">Hardware</a>
      <a href="#" class="dropdown-item">Services</a>
    </div>
    <div>
      <a href="#" class="dropdown-item">Support</a>
      <a href="#" class="dropdown-item">Community</a>
      <a href="#" class="dropdown-item">Partners</a>
    </div>
  </dropdown-panel>
</dropdown-component>

For nested menus, use the opens="right" attribute to make panels open to the right:

<dropdown-component>
  <dropdown-trigger>Resources</dropdown-trigger>
  <dropdown-panel>
    <a href="#" class="dropdown-item">Documentation</a>

    <!-- Nested dropdown -->
    <dropdown-component>
      <dropdown-trigger class="dropdown-item">Support</dropdown-trigger>
      <dropdown-panel opens="right">
        <a href="#" class="dropdown-item">Contact Us</a>
        <a href="#" class="dropdown-item">Help Center</a>
        <a href="#" class="dropdown-item">FAQ</a>
      </dropdown-panel>
    </dropdown-component>
  </dropdown-panel>
</dropdown-component>

Panel Attributes

The <dropdown-panel> component supports the following attributes:

wide - Full-Width Mega Menu

  • 🧩 Full-width panel, designed for larger navigation menus
  • Add the wide attribute: <dropdown-panel wide>
  • Supports multiple columns for richer layouts
  • Use when you have multiple categories or larger navigation needs

opens="right" - Right-Opening Panels

  • 🧩 Right-opening panel, perfect for nested menus
  • Add opens="right" attribute: <dropdown-panel opens="right">
  • Opens to the right of the trigger instead of below
  • Use for submenus and nested navigation

Default (Popover Style)

  • 🧩 Compact popover panel, positioned below the trigger button
  • No attributes needed - this is the default behavior
  • Great for short or simple option lists
  • Use when you need a small group of links or actions

All styles are accessible, keyboard-friendly, and customizable!

Styling

The component includes minimal styling by default. This makes it easy to integrate into any project, whether you're using CSS, Tailwind, CSS-in-JS, or another approach.

The component includes only essential functional styles:

  • CSS-based positioning logic (uses :has() to set relative/static based on wide attribute)
  • Show/hide visibility states
  • Hover bridge for better UX

Example: Custom CSS

dropdown-panel {
  background-color: #ffffff;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
  padding: 0.5rem 0;
  min-width: 200px;
  border-radius: 4px;
  z-index: 1000;
  /* Avoid overflow: hidden - it clips nested panels */
}

/* Add animations for popover panels */
dropdown-panel:not([wide]) {
  transform: translateY(5px) scale(0.98);
  transition: all 200ms ease-out;
}

dropdown-component:hover > dropdown-panel:not([wide]),
dropdown-panel:not([wide])[aria-hidden='false'] {
  transform: translateY(0) scale(1);
}

/* Style dropdown items */
.dropdown-item {
  display: block;
  padding: 0.5rem 1rem;
  color: #333;
  text-decoration: none;
}

.dropdown-item:hover {
  background-color: #f0f5ff;
}

Example: Tailwind CSS

<dropdown-component>
  <dropdown-trigger class="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700">
    Menu
  </dropdown-trigger>
  <dropdown-panel class="bg-white rounded-lg shadow-lg p-2 min-w-[200px] z-50">
    <a href="#" class="block px-4 py-2 hover:bg-gray-100 rounded">Option 1</a>
    <a href="#" class="block px-4 py-2 hover:bg-gray-100 rounded">Option 2</a>
  </dropdown-panel>
</dropdown-component>

Adding Dropdown Indicators

Use HTML elements for dropdown arrows (not CSS pseudo-elements, which interfere with the hover bridge):

<dropdown-trigger>
  Menu
  <span class="dropdown-arrow">
    <svg viewBox="0 0 12 12" fill="currentColor">
      <path d="M6 8L2 4h8z" />
    </svg>
  </span>
</dropdown-trigger>

Important: Avoid using ::after or ::before pseudo-elements on dropdown-trigger for visual indicators - they can block the invisible hover bridge that prevents the dropdown from closing.

See the demo/index.html file for complete styling examples.

API

Components

  • <dropdown-component>: The main container that coordinates everything
  • <dropdown-trigger>: The element that toggles the dropdown open/close
  • <dropdown-panel>: The dropdown content container (supports wide attribute for full-width mega menus)

Methods

// Get reference to the component
const dropdown = document.querySelector('dropdown-component');

// Show the dropdown
dropdown.show();

// Hide the dropdown
dropdown.hide();

Events

The dropdown component is fully compatible with standard event listeners:

const dropdown = document.querySelector('dropdown-component');

dropdown.addEventListener('mouseleave', () => {
  // Do something when mouse leaves dropdown
});

Accessibility

This component follows web accessibility best practices:

  • Semantic HTML structure without unnecessary ARIA menu roles
  • ARIA states and properties (aria-expanded, aria-controls, aria-hidden, aria-labelledby)
  • Keyboard navigation support:
    • Tab: Move between focusable elements
    • Space/Enter: Toggle dropdown open/closed
    • Escape: Close current level only (nested menus close progressively)
  • Focus management returns to trigger when closing
  • role="button" on trigger for proper semantic meaning

Nested Menu Behavior: When Escape is pressed in a nested submenu, only that submenu closes and focus returns to its trigger. This allows users to navigate back through menu levels progressively.

Note: This component intentionally does not use ARIA menu or menubar roles, following best practices for site navigation. These roles are designed for application menus (like File/Edit menus in desktop software), not website navigation dropdowns.

Browser Support

  • Chrome/Edge (latest)
  • Firefox (latest)
  • Safari (latest)
  • Other modern browsers that support Custom Elements v1

License

MIT