Standard Dropmenu
Action menu for tasks like edit, duplicate, share, or delete. Use buttons for items that trigger actions on the current page
<div class="nds-dropmenu">
<button class="nds-btn nds-secondary-outline nds-dropmenu-trigger">
<i class="nds-icon nds-hgi-menu-01" aria-hidden="true"></i>
<span class="nds-label">Actions</span>
</button>
<div class="nds-dropmenu-menu" hidden>
<div class="nds-dropmenu-scroll">
<button class="nds-btn nds-subtle nds-dropmenu-item">
<i class="hgi hgi-stroke hgi-edit-02"></i>
<span class="nds-label">Edit</span>
</button>
<button class="nds-btn nds-subtle nds-dropmenu-item">
<i class="nds-icon nds-hgi-copy-01"></i>
<span class="nds-label">Duplicate</span>
</button>
<button class="nds-btn nds-subtle nds-dropmenu-item">
<i class="nds-icon nds-hgi-share-01" aria-hidden="true"></i>
<span class="nds-label">Share</span>
</button>
<hr class="nds-divider">
<button class="nds-btn nds-subtle nds-dropmenu-item nds-destructive">
<i class="hgi hgi-stroke hgi-delete-02"></i>
<span class="nds-label">Delete</span>
</button>
</div>
</div>
</div>
Navigation Dropmenu
Menu items that navigate to other pages. Use anchor elements when each item is a link rather than an action
<div class="nds-dropmenu">
<button class="nds-btn nds-secondary-outline nds-dropmenu-trigger">
<span class="nds-label">Account</span>
<i class="hgi hgi-stroke hgi-user-circle"></i>
</button>
<div class="nds-dropmenu-menu" hidden>
<div class="nds-dropmenu-scroll">
<a href="#" class="nds-btn nds-subtle nds-dropmenu-item">
<i class="hgi hgi-stroke hgi-user-account"></i>
<span class="nds-label">Profile</span>
</a>
<a href="#" class="nds-btn nds-subtle nds-dropmenu-item">
<i class="hgi hgi-stroke hgi-settings-01"></i>
<span class="nds-label">Settings</span>
</a>
<a href="#" class="nds-btn nds-subtle nds-dropmenu-item">
<i class="hgi hgi-stroke hgi-help-circle"></i>
<span class="nds-label">Help</span>
</a>
<hr class="nds-divider">
<a href="#" class="nds-btn nds-subtle nds-dropmenu-item">
<i class="hgi hgi-stroke hgi-logout-01"></i>
<span class="nds-label">Sign out</span>
</a>
</div>
</div>
</div>
Scrollable Menu with No Auto-Close
Use nds-dropmenu-scroll for scrollable content areas and data-no-auto-close to keep the menu open when interacting with form controls
<div class="nds-dropmenu">
<button class="nds-btn nds-neutral nds-menu-btn nds-dropmenu-trigger">
<i class="hgi hgi-stroke hgi-settings-02"></i>
<span class="nds-label">Settings</span>
</button>
<div class="nds-dropmenu-menu" hidden style="min-width: 220px;">
<div class="nds-dropmenu-scroll">
<!-- data-no-auto-close keeps menu open on interaction -->
<fieldset class="nds-dropmenu-group nds-form-group nds-check-group"
data-no-auto-close>
<legend class="nds-label">Notifications</legend>
<div class="nds-form-container nds-switch-container">
<div class="nds-form-header">
<label for="setting-email">
<span class="nds-label">Email</span>
</label>
</div>
<div class="nds-form-control">
<div class="nds-switch">
<input type="checkbox" id="setting-email"
class="nds-switch-input" checked>
<div class="nds-switch-track">
<div class="nds-switch-thumb"></div>
</div>
</div>
</div>
</div>
<!-- more switches... -->
</fieldset>
<hr class="nds-divider">
<fieldset class="nds-dropmenu-group nds-form-group nds-check-group"
data-no-auto-close>
<legend class="nds-label">Display</legend>
<div class="nds-form-container nds-check-container">
<div class="nds-form-header">
<label for="setting-compact">
<span class="nds-label">Compact view</span>
</label>
</div>
<div class="nds-form-control">
<input type="checkbox" id="setting-compact" class="nds-check">
</div>
</div>
<!-- more checkboxes... -->
</fieldset>
</div>
<div class="nds-dropmenu-footer">
<hr class="nds-divider">
<div class="nds-dropmenu-action nds-grid">
<button class="nds-btn nds-secondary nds-dropmenu-item"
type="button" data-no-auto-close>
<span class="nds-label">Reset</span>
</button>
<button class="nds-btn nds-primary nds-dropmenu-item"
type="button">
<span class="nds-label">Save</span>
</button>
</div>
</div>
</div>
</div>
Dropmenu Inside Table
Row-level action menus work inside tables without being clipped by the table's rounded corners or overflow boundary. The menu auto-detects the clipping ancestor and switches to viewport-anchored positioning; scroll or resize dismisses the menu.
| Name | Role | Status | |
|---|---|---|---|
| Nora Al-Zahrani | Administrator | Active |
|
| Yousef Al-Harbi | Editor | Away |
|
| Layla Al-Qahtani | Viewer | Offline |
|
<table class="nds-table">
<thead>
<tr>
<th>Name</th>
<th>Role</th>
<th>Status</th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td>Nora Al-Zahrani</td>
<td>Administrator</td>
<td>
<span class="nds-tag nds-sm" data-status="success">
<span class="nds-label">Active</span>
</span>
</td>
<td>
<div class="nds-dropmenu">
<button class="nds-btn nds-sm nds-subtle nds-dropmenu-trigger"
aria-label="Row actions">
<i class="hgi hgi-stroke hgi-more-horizontal-circle-01"></i>
</button>
<div class="nds-dropmenu-menu" hidden>
<div class="nds-dropmenu-scroll">
<button class="nds-btn nds-subtle nds-dropmenu-item">
<i class="hgi hgi-stroke hgi-edit-02"></i>
<span class="nds-label">Edit</span>
</button>
<button class="nds-btn nds-subtle nds-dropmenu-item">
<i class="nds-icon nds-hgi-copy-01"></i>
<span class="nds-label">Duplicate</span>
</button>
<hr class="nds-divider">
<button class="nds-btn nds-subtle nds-dropmenu-item
nds-destructive">
<i class="hgi hgi-stroke hgi-delete-02"></i>
<span class="nds-label">Delete</span>
</button>
</div>
</div>
</div>
</td>
</tr>
<!-- more rows... -->
</tbody>
</table>
Built-in Features
Dropmenus initialize automatically on page load and can be dynamically reinitialized using NDS.Dropmenu.reinit() for content added after initial load.
Menus stay fully visible regardless of where the trigger sits on the page, flipping direction when near screen edges.
Full keyboard support with arrow keys, Home, End, Tab, Escape, and special handling for input fields inside menus using Alt+Arrow combinations.
ARIA roles and states are applied automatically, and animations respect the user's reduced-motion preference.
Menu items with data-no-auto-close stay open on click, letting users interact with checkboxes, inputs, and filter controls without interruption.
Programmatic control with instance methods open(), close(), toggle(), and custom events for state changes.
Usage Guidelines
Best Practices
- Use dropmenus for action lists when screen space is limited and actions don't need to be immediately visible
- Use for contextual actions that apply to a specific item, like row-level edit, delete, or share
- Use for secondary navigation that doesn't need permanent visibility, like account or settings links
- Use with
data-no-auto-closefor filter panels where users select multiple options before closing - Group related actions together and use
<hr class="nds-divider">to separate action groups - Keep menus focused with 3-8 items. If you need more, consider restructuring into multiple menus or a different pattern
- Icons are optional but recommended for faster visual scanning when actions have clear iconic representations
- Don't use for primary navigation that should always be visible. Use the Header or Side Nav instead
- Don't use for a single toggle action. A Switch or standalone Button is simpler
- Don't use for complex multi-step forms. Use a Modal or Drawer for more space
Modifier Classes
| Class | Description |
|---|---|
nds-destructive |
Applies destructive (red) styling to a menu item. Place destructive actions last in the menu for visual separation. |
nds-dropmenu-footer |
Sticky footer area that stays visible while the menu content scrolls. Place outside .nds-dropmenu-scroll. |
nds-dropmenu-action |
Action bar inside the footer for buttons like Clear and Apply. Combine with nds-grid for side-by-side layout. |
nds-dropmenu-group |
Groups form controls or related items inside the menu with consistent spacing. |
Data Attributes
| Attribute | Description |
|---|---|
data-no-auto-close |
Set on a .nds-dropmenu-item to prevent the menu from closing when that item is clicked. Use for checkboxes, inputs, and filter controls that need multiple interactions. |
CSS Custom Properties
| Property | Default | Description |
|---|---|---|
--menu-padding |
8px | Inner padding of the menu container |
--dropmenu-min-width |
150px | Minimum width of the menu. Override inline or via CSS to fit your content. |
--dropmenu-slide |
8px | Distance the menu slides during open/close animation |
JavaScript API
// ── Auto-initialization ────────────────────────────────────
// Dropmenus initialize automatically on page load
// ── Reinitialization ───────────────────────────────────────
// Call after dynamically adding new dropmenus to the page
NDS.Dropmenu.reinit();
// ── Manual creation ────────────────────────────────────────
const element = document.querySelector('.nds-dropmenu');
const instance = NDS.Dropmenu.create(element);
// ── Instance methods ───────────────────────────────────────
// Access instance via element.ndsDropmenu
const dropmenu = document.querySelector('.nds-dropmenu');
const instance = dropmenu.ndsDropmenu;
instance.open(); // Open the menu
instance.close(); // Close the menu
instance.toggle(); // Toggle open/closed state
instance.destroy(); // Remove listeners and replace the DOM node (external references will be invalidated)
// ── Events ─────────────────────────────────────────────────
// Listen for state changes
document.addEventListener('nds:dropmenu:opened', (e) => {
// e.detail: { dropmenu, trigger, menu, isOpen }
console.log('Menu opened:', e.detail.dropmenu);
});
document.addEventListener('nds:dropmenu:closed', (e) => {
// e.detail: { dropmenu, trigger, menu, isOpen }
console.log('Menu closed:', e.detail.dropmenu);
});
// ── Keyboard navigation ────────────────────────────────────
// Trigger button:
// Enter/Space: toggle menu
// ArrowDown: open and focus first item
// ArrowUp: open and focus last item
//
// Inside menu:
// ArrowDown/Up: navigate items
// Home/End: jump to first/last item
// Tab/Shift+Tab: navigate focusable elements
// Escape: close menu and return focus to trigger
//
// Inside input fields:
// Alt+ArrowDown/Up: navigate menu items
// Ctrl+Home/End: jump to first/last item