Dropdown

A fully accessible dropdown component with smooth animations, backdrop blur, keyboard navigation, grouped options, disabled items, and comprehensive dark mode support. Built with modern CSS effects and vanilla JavaScript.

Basic Usage

Add data-name to the wrapper to name the hidden input for form use.

<div class="dropdown" data-name="framework" style="width:220px">
  <button class="dropdown-btn">Select framework…</button>
  <div class="dropdown-content">
    <div class="dropdown-label">Frontend</div>
    <div class="dropdown-item" data-value="react">React</div>
    <div class="dropdown-item" data-value="vue">Vue</div>
    <div class="dropdown-item active" data-value="svelte">Svelte</div>
    <div class="dropdown-divider"></div>
    <div class="dropdown-label">Backend</div>
    <div class="dropdown-item" data-value="express">Express</div>
    <div class="dropdown-item" data-value="fastify">Fastify</div>
  </div>
</div>

Dropdown Structure

Every dropdown consists of four main parts:

  • .dropdown — Root container with data-name for form integration
  • .dropdown-btn — Toggle button showing the current selection
  • .dropdown-content — Animated menu panel with backdrop blur effect
  • .dropdown-item — Individual selectable options inside the content

Backdrop Blur Effect

The .dropdown-content uses backdrop-filter: blur(12px) for a modern frosted-glass effect. This creates visual depth and elegance while maintaining readability.

💡 Progressive enhancement The dropdown is fully functional even in browsers that don't support backdrop-filter. The blur is a visual enhancement, not a requirement for functionality.

Animations

The dropdown content animates in smoothly using a combination of opacity, scale, and transform properties. The toggle button's arrow rotates 180° when the content is open.

/* Animation on enter */
.dropdown.open .dropdown-content {
  opacity: 1;
  transform: translateY(0) scale(1);
  pointer-events: auto;
  transition: all 0.25s cubic-bezier(0.25, 0.8, 0.25, 1);
}

/* Animation on exit */
.dropdown-content {
  opacity: 0;
  transform: translateY(-10px) scale(0.95);
  pointer-events: none;
}

Grouped Items with Labels and Dividers

Organize dropdown items into logical groups using .dropdown-label for headers and .dropdown-divider for visual separation.

<div class="dropdown-label">🎨 Design</div>
<div class="dropdown-item" data-value="figma">Figma</div>
<div class="dropdown-item" data-value="sketch">Sketch</div>
<div class="dropdown-divider"></div>
<div class="dropdown-label">⚙️ Development</div>
<div class="dropdown-item" data-value="vscode">VS Code</div>

Disabled Items

Use aria-disabled="true" on items that should not be selectable. This is useful for placeholder text, "Coming soon" messages, or unavailable options.

<div class="dropdown-item" data-value="" aria-disabled="true">
  Coming soon…
</div>

Active State

Add the class active to a .dropdown-item to indicate the currently selected option. This item will have a bold font weight and light background highlight.

Scrollable Content

Large dropdowns automatically scroll when content exceeds max-height: 15rem. The scrollbar styling is consistent with the theme and adapts to dark mode.

📜 Scrollbar styling Custom scrollbar styles use scrollbar-width: thin and webkit pseudo-elements for consistent appearance across browsers. The scrollbar adapts its color in dark mode.

Initialisation

// Dropdowns are automatically initialized with initAll()
// No manual initialization needed!

import('@kerkhoff-ict/solora/dist/index.js')
  .then(sol => sol.initAll());

Keyboard Support

KeyAction
Enter / SpaceOpen dropdown
/ Navigate between items
EnterSelect focused item
EscapeClose dropdown
TabMove focus out (closes dropdown)

Form Integration

Each dropdown automatically creates a hidden <input type="hidden"> with the name specified in data-name. This input holds the selected item's data-value.

<!-- Rendered output after selection -->
<input type="hidden" name="framework" value="react">

Dark Mode

All dropdown styles automatically adapt when dark class is added to <html>. The backdrop blur effect remains consistent, while text, background, and hover states invert appropriately.

Toggle your theme to see dark mode in action. The dropdown will instantly adapt.

/* Light mode (default) */
.dropdown-btn {
  background: var(--color-bg, #fefefe);
  color: var(--color-text-dark, #000);
  border: 1px solid rgba(0, 0, 0, 0.1);
}

/* Dark mode */
:root.dark .dropdown-btn {
  background: #1c1c1e;
  color: #f0f0f0;
  border: 1px solid rgba(255, 255, 255, 0.2);
}

CSS Classes Reference

Class / AttributeTypeDescription
.dropdownContainerRoot wrapper; apply dimensions here
data-nameAttributeNames the hidden input field for forms
.dropdown-btnInteractiveToggle button; displays current selection
.dropdown-btn:afterPseudoRotates arrow icon when open via transform
.dropdown-contentPanelMenu container with backdrop blur and scroll
.dropdown.openStateApplied when menu is visible
.dropdown-itemOptionIndividual selectable item
.dropdown-item.activeStateHighlights the selected item (bold + background)
aria-disabled="true"AttributeMarks items as non-selectable (grayed out)
.dropdown-labelLabelGroup header; not selectable
.dropdown-dividerDividerThin horizontal line between groups
data-valueAttributeValue stored in hidden input when selected

CSS Customization

Override these CSS variables to customize dropdown appearance across your entire site:

:root {
  /* Button */
  --dropdown-btn-bg: var(--color-bg, #fefefe);
  --dropdown-btn-text: var(--color-text-dark, #000);
  --dropdown-btn-border: rgba(0, 0, 0, 0.1);
  --dropdown-btn-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);

  /* Content panel */
  --dropdown-content-blur: 12px;
  --dropdown-content-max-height: 15rem;
  --dropdown-content-shadow: 0 12px 32px rgba(0, 0, 0, 0.12);

  /* Items */
  --dropdown-item-hover-bg: rgba(0, 0, 0, 0.05);
  --dropdown-item-active-bg: rgba(0, 0, 0, 0.1);
}

Accessibility

♿ Best practices
  • Dropdowns are fully keyboard navigable. Use / to navigate, Enter to select.
  • ARIA attributes are handled automatically by the JavaScript initialization.
  • Disabled items use aria-disabled="true" so screen readers announce them as unavailable.
  • The hidden input respects the data-name attribute for proper form submission.
  • Always pair dropdowns with visible labels or use aria-label on the toggle button.

Performance Tips

⚡ Optimization
  • For dropdowns with many items (50+), ensure max-height is set to keep rendering efficient.
  • Backdrop blur is GPU-accelerated, but avoid excessive blur values on low-end devices.
  • Re-initialize dropdown if content changes dynamically via initAll().