Skip to main content

Menu

Thin wrapper over Button with popup support. Uses PopupList by default.

Quick start
import { Menu } from "mates-ui";





Menu({
  label: "File ▾",
  variant: "outlined",
  items: [
    { id: "new", label: "New" },
    { id: "open", label: "Open…" },
  ],
  onSelect: (_ids, item) => console.log(item?.id),
  popup: { position: "bottom-start" },
});
      
import { html, atom, renderApp } from 'mates';
import { Menu, Text } from 'mates-ui';
import { FolderOpenIcon, NoteAddIcon, SaveIcon } from 'mates-icons';

const App = () => {
const last = atom(null);
return () => html`
<x-row gap="var(--md-space-4)" align="center">
${Menu({
label: "File ▾",
variant: "outlined",
items: [
{ id: "new", label: "New", icon: NoteAddIcon() },
{ id: "open", label: "Open…", icon: FolderOpenIcon() },
{ type: "divider", label: "" },
{ id: "save", label: "Save", icon: SaveIcon() },
],
onSelect: (_ids, item) => last.set(item?.id ?? null),
popup: { position: "bottom-start" },
})}
${last() ? Text("Last: " + last(), { type: "body-sm", color: "muted" }) : html``}
</x-row>
`;
};

renderApp(App, document.getElementById('app'));
import { html, atom, renderApp } from 'mates';
import { Menu, Text } from 'mates-ui';
import { DeleteIcon, EditIcon, MoreVertIcon } from 'mates-icons';

const App = () => {
const last = atom(null);
return () => html`
<x-row gap="var(--md-space-4)" align="center">
${Menu({
label: "",
variant: "outlined",
icon: MoreVertIcon(),
attr: { "aria-label": "More actions" },
items: [
{ id: "edit", label: "Edit", icon: EditIcon() },
{ id: "delete", label: "Delete", icon: DeleteIcon() },
],
onSelect: (_ids, item) => last.set(item?.id ?? null),
popup: { position: "bottom-end", matchAnchorWidth: false },
})}
${last() ? Text("Last: " + last(), { type: "body-sm", color: "muted" }) : html``}
</x-row>
`;
};

renderApp(App, document.getElementById('app'));
import { html, renderApp } from 'mates';
import { Menu } from 'mates-ui';

const ITEMS = [{ id: "a", label: "Option A" }, { id: "b", label: "Option B" }];

const App = () => () => html`
<x-row gap="var(--md-space-3)" wrap>
${Menu({ label: "Top", variant: "outlined", size: "sm", items: ITEMS, onSelect: () => {}, popup: { position: "top-start" } })}
${Menu({ label: "Bottom", variant: "outlined", size: "sm", items: ITEMS, onSelect: () => {}, popup: { position: "bottom-start" } })}
${Menu({ label: "Right", variant: "outlined", size: "sm", items: ITEMS, onSelect: () => {}, popup: { position: "right-start" } })}
</x-row>
`;

renderApp(App, document.getElementById('app'));
import { html, atom, renderApp } from 'mates';
import { Menu, Text } from 'mates-ui';

const App = () => {
const checked = atom(["email"]);
return () => html`
<x-row gap="var(--md-space-4)" align="center">
${Menu({
label: "Columns",
variant: "outlined",
checkType: "check",
selected: checked(),
items: [
{ id: "name", label: "Name" },
{ id: "email", label: "Email" },
{ id: "role", label: "Role" },
],
onSelect: (ids) => checked.set(ids),
closeOnSelect: false,
popup: { position: "bottom-start", matchAnchorWidth: false },
})}
${Text("Selected: " + (checked().join(", ") || "none"), { type: "body-sm", color: "muted" })}
</x-row>
`;
};

renderApp(App, document.getElementById('app'));
import { html, renderApp } from 'mates';
import { Menu, FilledButton, DangerButton } from 'mates-ui';

const App = () => () => html`
<x-row>
${Menu({
label: "Custom panel",
panel: html`
<div style="padding:0.75rem 1rem;min-width:12rem;">
<strong>Quick actions</strong>
<x-row gap="var(--md-space-2)" style="margin-top:0.5rem;">
${FilledButton("Save", { size: "sm" })}
${DangerButton("Delete", { size: "sm" })}
</x-row>
</div>
`,
popup: { position: "bottom-start", matchAnchorWidth: false },
})}
</x-row>
`;

renderApp(App, document.getElementById('app'));

Menu

import { Menu } from "mates-ui";
Prop Type Default Description
attr AttrMap HTML attributes on the root element.
classes string | string[] Extra root classes — joined and appended after built-in classes.
data DataAttrMap Root `data-*` map (`testId` → `data-testid`). `testId` prop / `attr` win over `data`.
id string Root `id` shorthand (`attr.id` wins). Form native-control `id` props are unchanged.
items PopupListItemData[] Default list items (used when `panel` is not provided).
label* string | TemplateResult Trigger text/content rendered by Button.
on OnEventMap DOM event handlers on the root element.
onSelect (ids, item, e) => void Selection callback from PopupList.
panel TemplateResult Optional custom panel. If provided, bypasses default PopupList.
popup PopupPlacement | PopupOptions Popup options object passed through to Button's popup support.
style StyleMap Inline CSS on the root element.