Skip to content

Menu

A menu that opens next to its button. It’s positioned with Floating UI — it flips when there isn’t room, stays on screen and follows the button while scrolling — and sits in the browser’s top layer, so no parent’s overflow clips it.

---
import { Button, Icon, Menu } from 'bws-astro-ui';
import { ChevronDown, LogOut, Settings, UserRound } from 'bws-astro-ui/icons';
---
<Menu
id="account"
items={[
{ title: 'Profile', href: '/profile', icon: UserRound },
{ title: 'Settings', value: 'settings', icon: Settings },
{ divider: true },
{ title: 'Log out', value: 'logout', icon: LogOut, color: 'error' },
]}
>
<Button slot="activator" variant="outlined">Account <Icon icon={ChevronDown} /></Button>
</Menu>

The activator should be a button, so it can be reached and opened with the keyboard.

Field Description
title the text
href makes the item a link
value for items that aren’t links — sent with the menu:select event (defaults to the title)
icon any icon <Icon> accepts
color e.g. error for a destructive action
disabled shown, but can’t be chosen and is skipped by the arrow keys
divider { divider: true } draws a line between groups

Choosing an item closes the menu. Items without href fire menu:select on the menu:

<script>
document.getElementById('account')?.addEventListener('menu:select', (event) => {
const { value, title } = (event as CustomEvent).detail;
if (value === 'logout') logOut();
});
</script>

It follows the WAI-ARIA menu button pattern:

Key On the button In the menu
Enter / Space / ↓ opens, focuses the first item Enter / Space chooses the item
↑ opens, focuses the last item previous item (wraps)
↓ next item (wraps)
Home / End first / last item
letters jump to the next item starting with them
Escape closes closes, focus back to the button
Tab closes and moves on

location takes any Floating UI placement: bottom-start (default), bottom, bottom-end, top-start, top, top-end, left-start, left, left-end, right-start, right, right-end. When there isn’t room, the menu flips to the opposite side.

openOnHover opens the menu while the pointer is over the button or the menu — handy for dropdowns in a top navigation. On touch screens it opens on tap, and the keyboard works as usual.

Without items, the default slot is shown in the popup — a small form, a card, filters. Set closeOnContentClick={false} so clicks inside don’t close it; Escape and clicks outside still do.

<Menu closeOnContentClick={false} class="w-72">
<Button slot="activator">Apply a coupon</Button>
<TextInput label="Coupon code" variant="outlined" />
<Button block>Apply</Button>
</Menu>
Prop Type Default
items menu entries (see Items) —
location a Floating UI placement bottom-start
openOnHover boolean false
closeOnContentClick boolean — close after a click inside true
id string — the menu’s id, for menu:select listeners generated
class string — e.g. a width —
Slot Content
activator the button that opens the menu
default free-form content, when there are no items
Event When
menu:select an item without href is chosen — detail: { value, title }, bubbles
Created byBanach Web SolutionsBanach Web Solutions