Dropdown Menu
A keyboard-navigable dropdown menu with icons, shortcuts, and danger items.
Rendering Dropdown Menu…
Installation
Copy the source into your project with the CLI. It lands under @/components/ui and is yours to edit.
npx mlola-ui add dropdown-menuUsage
import { DropdownMenu } from "@/components/ui/dropdown-menu";
export default function Example() {
return (
<DropdownMenu
trigger="File"
label="File"
items={[
{ label: "New", shortcut: "⌘N" },
{ label: "Duplicate" },
{ label: "Delete", danger: true, separatorBefore: true },
]}
/>
);
}Styling comes from the engine stylesheet and the nearest theme. Set it once at the root:
<html data-theme="graphite" data-mode="light">Examples
Row actions
Icons and shortcuts help recognition; a destructive item sits last, apart from the rest.
Rendering Row actions…
HTML
Without React, write this markup and load @mlola-ui/behavior once. It runs the keyboard, focus and state for every element marked data-ml="dropdown-menu", including markup added later, and needs no build step.
<div class="ml-dropdown" data-ml="dropdown-menu">
<button class="ml-dropdown-trigger" type="button" aria-haspopup="menu" aria-expanded="false">
<span class="ml-dropdown-trigger-label">File</span>
<svg class="mlola-glyph" width="1em" height="1em" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="m6 9 6 6 6-6"/></svg>
</button>
<div class="ml-dropdown-menu" role="menu" aria-label="File" data-align="start" hidden>
<button class="ml-dropdown-item" type="button" role="menuitem">New</button>
<button class="ml-dropdown-item" type="button" role="menuitem">Open</button>
<button class="ml-dropdown-item" type="button" role="menuitem" data-danger>Delete</button>
</div>
</div><script type="module">
import { observe } from "@mlola-ui/behavior";
observe();
</script>Options
| Prop | Values | Default | Description |
|---|---|---|---|
align | startend | start | — |
variant | buttonicon | button | button shows the trigger with a chevron; icon is a small icon-only trigger, such as a card's or a column's "…" menu. |
Every prop with a fixed set of values, read from the exported TypeScript types with its doc comment. Open the Code tab above for the rest of the API.
Classes and attributes
A class names each element; data-* and aria-* attributes carry its variant and state. The values listed are the ones the stylesheet draws; the default needs no attribute.
| Class | Attributes |
|---|---|
ml-dropdown | — |
ml-dropdown-trigger | aria-expanded="true"data-variant="icon" |
ml-dropdown-trigger-label | — |
ml-dropdown-chevron | — |
ml-dropdown-menu | data-align="end"data-side="top" |
ml-dropdown-label | — |
ml-dropdown-item | data-dangerdata-highlighted |
ml-dropdown-item-icon | — |
ml-dropdown-item-label | — |
ml-dropdown-shortcut | — |
ml-dropdown-separator | — |
ml-dropdown-status | — |
Accessibility and theming
- Semantic elements, accessible names and state relationships are part of the contract.
- Keyboard, pointer and touch paths are operable; focus stays visible in every theme.
- Light and dark modes pass WCAG AA contrast in all 5 canonical themes.
- Reduced motion and forced colors keep meaning and operation.
Dependencies
Installed alongside this component. No third-party UI runtime is ever added.
@mlola-ui/behavior@mlola-ui/icons