Menu
MD3 menu — a list of actions hanging off a trigger.
Walkthrough
1. Basic
The trigger snippet gets the props that wire it to the menu. The overflow on a row or a card, where three buttons would crowd it.
<script lang="ts"> import { Button, Menu, MenuItem } from 'omaris';</script><Menu label="Project actions"> {#snippet trigger(props)} <Button variant="outlined" {...props}>Actions</Button> {/snippet} <MenuItem>Rename</MenuItem> <MenuItem>Duplicate</MenuItem> <MenuItem tone="destructive">Delete</MenuItem></Menu> 2. Icons and shortcuts
Icons and shortcuts earn their place on a menu people open often; inset lines up a row without an icon beside the ones that have one.
<script lang="ts"> import { IconButton, Menu, MenuItem, MenuLabel } from 'omaris';</script><Menu label="Edit"> {#snippet trigger(props)} <IconButton aria-label="Edit menu" {...props}> <svg viewBox="0 0 24 24" fill="currentColor"> <circle cx="12" cy="5" r="1.6" /><circle cx="12" cy="12" r="1.6" /><circle cx="12" cy="19" r="1.6" /> </svg> </IconButton> {/snippet} <MenuLabel>Edit</MenuLabel> <MenuItem shortcut="⌘C"> {#snippet icon()} ... {/snippet} Copy </MenuItem> <MenuItem shortcut="⌘V"> {#snippet icon()} ... {/snippet} Paste </MenuItem> <MenuItem inset shortcut="⌘⌫" tone="destructive">Delete</MenuItem></Menu> 3. Selection
selected draws the tick. selected={false} is meaningfully different from leaving it off: it reserves the space, so a list of choices does not shuffle sideways when one is picked. radio makes each row one of a set, which is what a screen reader announces.
<script lang="ts"> import { Button, Menu, MenuItem } from 'omaris'; let sort = $state('Newest first');</script><Menu label="Sort by" closeOnSelect> {#snippet trigger(props)} <Button variant="tonal" {...props}>Sort: {sort}</Button> {/snippet} <MenuItem radio selected={sort === 'Newest first'} onclick={() => (sort = 'Newest first')}> Newest first </MenuItem> <MenuItem radio selected={sort === 'Oldest first'} onclick={() => (sort = 'Oldest first')}> Oldest first </MenuItem> <MenuItem radio selected={sort === 'Largest total'} onclick={() => (sort = 'Largest total')}> Largest total </MenuItem></Menu> 5. Placement
side and align place it, and it flips itself when there is no room. align="end" for a menu hanging off the far end of a toolbar.
<script lang="ts"> import { Button, Menu, MenuItem } from 'omaris';</script><Menu side="top" align="start" label="Upwards"> {#snippet trigger(props)} <Button variant="outlined" size="xs" {...props}>Top</Button> {/snippet} <MenuItem>Opens above</MenuItem></Menu><Menu side="right" align="start" label="Sideways"> {#snippet trigger(props)} <Button variant="outlined" size="xs" {...props}>Right</Button> {/snippet} <MenuItem>Opens beside</MenuItem></Menu><Menu matchWidth label="Matched"> {#snippet trigger(props)} <Button variant="outlined" size="xs" class="w-48 max-w-full" {...props}>matchWidth</Button> {/snippet} <MenuItem>As wide as the trigger</MenuItem></Menu>