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>Keyboard
Section titled “Keyboard”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
Section titled “Location”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.
Open on hover
Section titled “Open on hover”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.
Free-form content
Section titled “Free-form content”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 |