Skip to content

Dropdown Menu

A copy-paste modals & overlays component in pure HTML, CSS & vanilla JS. Zero dependencies, framework-agnostic, MIT-licensed.

Modals & OverlaysHTMLCSSJavaScriptany framework

Copy into your project

HTML
<div class="nuda-dropdown">
  <button class="nuda-dropdown__trigger" aria-haspopup="true" aria-expanded="false">
    Menu &#9662;
  </button>
  <div class="nuda-dropdown__menu" role="menu">
    <a href="#" class="nuda-dropdown__item" role="menuitem">Profile</a>
    <a href="#" class="nuda-dropdown__item" role="menuitem">Settings</a>
    <hr class="nuda-dropdown__divider" />
    <a href="#" class="nuda-dropdown__item nuda-dropdown__item--danger" role="menuitem">Logout</a>
  </div>
</div>
CSS
/* Dropdown Menu
   Animated dropdown with scale + fade entrance.
   Customize: --dropdown-bg, --dropdown-accent */

.nuda-dropdown {
  position: relative;
  display: inline-block;
}

.nuda-dropdown__trigger {
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 8px;
  padding: 0.5rem 1rem;
  color: #ccc;
  font-size: 0.85rem;
  cursor: pointer;
  transition: background 0.2s;
}

.nuda-dropdown__trigger:hover {
  background: rgba(255, 255, 255, 0.1);
}

.nuda-dropdown__menu {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  min-width: 160px;
  background: #141414;
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: 10px;
  padding: 0.25rem;
  opacity: 0;
  visibility: hidden;
  transform: translateY(-6px) scale(0.97);
  transform-origin: top left;
  transition: opacity 0.2s ease, transform 0.2s ease, visibility 0.2s ease;
  z-index: 100;
}

.nuda-dropdown.is-open .nuda-dropdown__menu {
  opacity: 1;
  visibility: visible;
  transform: translateY(0) scale(1);
}

.nuda-dropdown__item {
  display: block;
  padding: 0.5rem 0.75rem;
  border-radius: 6px;
  color: #ccc;
  font-size: 0.8rem;
  text-decoration: none;
  transition: background 0.15s;
}

.nuda-dropdown__item:hover {
  background: rgba(255, 255, 255, 0.06);
  color: #fff;
}

.nuda-dropdown__item--danger { color: #f87171; }
.nuda-dropdown__item--danger:hover { background: rgba(248, 113, 113, 0.08); }

.nuda-dropdown__divider {
  border: none;
  height: 1px;
  background: rgba(255, 255, 255, 0.06);
  margin: 0.25rem 0;
}

@media (prefers-reduced-motion: reduce) {
  .nuda-dropdown__menu { transition: none; }
}
JavaScript
/* Dropdown Menu — Toggle with .is-open class */

(function () {
  var dropdowns = document.querySelectorAll('.nuda-dropdown');
  dropdowns.forEach(function (dropdown) {
    var trigger = dropdown.querySelector('.nuda-dropdown__trigger');
    if (!trigger) return;

    trigger.addEventListener('click', function () {
      var isOpen = dropdown.classList.toggle('is-open');
      trigger.setAttribute('aria-expanded', String(isOpen));
    });

    document.addEventListener('click', function (e) {
      if (!dropdown.contains(e.target)) {
        dropdown.classList.remove('is-open');
        trigger.setAttribute('aria-expanded', 'false');
      }
    });
  });
})();

How to use Dropdown Menu

Paste the HTML where you need it and the CSS into a global stylesheet (or a <style> tag). Every class is prefixed nuda- so it never collides with Tailwind or your own styles. Tweak the CSS custom properties to match your design system.

Works in React, Vue, Svelte, Astro, Next.js, Nuxt, Laravel Blade, Django, Rails — or a single .html file. No npm install, no build step.

More modals & overlays components

← Browse all NudaUI components