Basic — leading icons + trailing shortcut text
Click the trigger; the menu opens anchored below it.
Selection — checkbox items keep the menu open
Long list — clamps to viewport and scrolls
Type-ahead: repeat the same first letter with a pause between presses (e.g. "s", pause, "s", pause, "s") to cycle Saudi Arabia → Singapore → Slovakia → South Africa → South Korea → Spain → Sweden → Switzerland. Space mid-word (e.g. "new", Space, "z" for "New Zealand") stays in the buffer instead of closing the menu.
Edge of viewport — flips above
Selection log
Sample usage
<!-- Trigger anywhere on the page; popovertarget points at the menu's id. -->
<material-button label="Edit…" trailing-icon="expand_more"
popovertarget="my-menu"></material-button>
<material-menu id="my-menu" anchor="#my-trigger">
<material-menu-item label="Cut" leading-icon="content_cut" trailing-text="⌘X" value="cut"></material-menu-item>
<material-menu-item label="Copy" leading-icon="content_copy" trailing-text="⌘C" value="copy"></material-menu-item>
<material-menu-item label="Paste" leading-icon="content_paste" trailing-text="⌘V" value="paste"></material-menu-item>
<material-menu-item label="Delete" leading-icon="delete" disabled value="delete"></material-menu-item>
<material-menu-item label="Settings…" leading-icon="settings" divider="top" value="settings"></material-menu-item>
</material-menu>
<!-- Listen for selections (event bubbles + composed). -->
<script>
document.getElementById('my-menu').addEventListener('materialMenuSelect', e => {
console.log('selected', e.detail.value);
});
</script>
<!-- Checkbox items: keep-open prevents auto-close; click anywhere on the row toggles the box. -->
<material-menu id="filters" anchor="#filter-btn">
<material-menu-item keep-open value="unread">
<material-checkbox slot="leading"></material-checkbox>
Unread
</material-menu-item>
<material-menu-item keep-open value="starred">
<material-checkbox slot="leading" checked></material-checkbox>
Starred
</material-menu-item>
<material-menu-item label="Apply" trailing-icon="check" divider="top" value="apply"></material-menu-item>
</material-menu>
<!-- Long lists: max-height clamps; viewport room is the other ceiling. -->
<material-menu id="picker" anchor="#picker-btn" max-height="320">…</material-menu>
<!-- Placement: bottom-start (default) | bottom-end | top-start | top-end.
Auto-flips to the opposite side when it would overflow the viewport. -->
<material-menu placement="bottom-end" offset="8">…</material-menu>
<!-- Programmatic open/close. The menu uses the HTML Popover API under the hood. -->
<script>
const menu = document.getElementById('my-menu');
menu.show(); // or: menu.open = true
menu.hide(); // or: menu.open = false
menu.addEventListener('materialMenuOpen', () => console.log('opened'));
menu.addEventListener('materialMenuClose', () => console.log('closed'));
</script>
<!-- Item anatomy -->
<material-menu-item
label="Notifications"
leading-icon="notifications"
trailing-icon="chevron_right"
supporting-text="3 new this week"
value="notifications"></material-menu-item>
<!-- Slots override the icon/text props for richer content (avatars, switches, etc.) -->
<material-menu-item value="profile">
<img slot="leading" src="/avatar.png" class="w-6 h-6 rounded-full" />
Mikhail
<span slot="trailing" class="text-xs">Online</span>
</material-menu-item>