Menu
A menu of actions.
Anatomy
<script>
import { Menu } from '@shardsui/svelte/menu'
</script>
<Menu.Root>
<Menu.Trigger />
<Menu.Portal>
<Menu.Backdrop />
<Menu.Positioner>
<Menu.Popup>
<Menu.Arrow />
<Menu.Item />
<Menu.LinkItem />
<Menu.Separator />
<Menu.SubmenuRoot>
<Menu.SubmenuTrigger />
</Menu.SubmenuRoot>
<Menu.Group>
<Menu.GroupLabel />
</Menu.Group>
<Menu.RadioGroup>
<Menu.GroupLabel />
<Menu.RadioItem>
<Menu.RadioItemIndicator />
</Menu.RadioItem>
</Menu.RadioGroup>
<Menu.CheckboxItem>
<Menu.CheckboxItemIndicator />
</Menu.CheckboxItem>
<Menu.Viewport />
</Menu.Popup>
</Menu.Positioner>
</Menu.Portal>
</Menu.Root>Examples
Open on hover
Add the openOnHover prop to <Menu.Trigger> to open the menu on pointer hover. Tune the timing with delay (how long the pointer must rest before it opens) and closeDelay (how long it lingers after the pointer leaves), both in milliseconds.
Checkbox items
<Menu.CheckboxItem> renders a menu item that toggles a setting on or off.
Radio items
<Menu.RadioGroup> and <Menu.RadioItem> turn a set of items into mutually exclusive choices, like radio buttons.
Close on click
Set closeOnClick to decide whether clicking an item dismisses the menu.
<!-- Close the menu when a checkbox item is clicked -->
<Menu.CheckboxItem closeOnClick />
<!-- Keep the menu open when an item is clicked -->
<Menu.Item closeOnClick={false} />Group labels
<Menu.GroupLabel> gives a <Menu.Group> or <Menu.RadioGroup> a heading.
Nested menu
Nest another menu inside the current one with <Menu.SubmenuRoot>, and mark the item that opens it with <Menu.SubmenuTrigger>.
<Menu.Root>
<Menu.Trigger />
<Menu.Portal>
<Menu.Positioner>
<Menu.Popup>
<Menu.Arrow />
<Menu.Item />
<!-- Submenu -->
<Menu.SubmenuRoot>
<Menu.SubmenuTrigger />
<Menu.Positioner>
<Menu.Popup>
<!-- Submenu items -->
</Menu.Popup>
</Menu.Positioner>
</Menu.SubmenuRoot>
</Menu.Popup>
</Menu.Positioner>
</Menu.Portal>
</Menu.Root>Navigate to another page
<Menu.LinkItem> renders a menu item as a link.
<Menu.LinkItem href="/projects">Go to Projects</Menu.LinkItem>Open a dialog
To open a dialog from a menu, hold the dialog's open state yourself and flip it from the item's onclick handler.
<script>
import { Dialog } from '@shardsui/svelte/dialog'
import { Menu } from '@shardsui/svelte/menu'
let dialogOpen = $state(false)
</script>
<Menu.Root>
<Menu.Trigger>Open menu</Menu.Trigger>
<Menu.Portal>
<Menu.Positioner>
<Menu.Popup>
<!-- Open the dialog when the menu item is clicked -->
<Menu.Item onclick={() => (dialogOpen = true)}>Open dialog</Menu.Item>
</Menu.Popup>
</Menu.Positioner>
</Menu.Portal>
</Menu.Root>
<!-- Control the dialog state -->
<Dialog.Root bind:open={dialogOpen}>
<Dialog.Portal>
<Dialog.Backdrop />
<Dialog.Popup>
<!-- Rest of the dialog -->
</Dialog.Popup>
</Dialog.Portal>
</Dialog.Root>Detached triggers
A menu's trigger can sit inside <Menu.Root> (as in the hero demo above) or somewhere else entirely. When the trigger and the menu content belong in different parts of the tree, create a handle with new Menu.Handle() and pass it to both the trigger and the root.
Only top-level menus support detached triggers; a submenu's trigger always stays inside its SubmenuRoot.
<script>
import { Menu } from '@shardsui/svelte/menu'
const demoMenu = new Menu.Handle()
</script>
<Menu.Trigger handle={demoMenu}>Actions</Menu.Trigger>
<Menu.Root handle={demoMenu}>
<Menu.Portal>
<Menu.Positioner>
<Menu.Popup>
<Menu.Item>Edit</Menu.Item>
<Menu.Item>Share</Menu.Item>
</Menu.Popup>
</Menu.Positioner>
</Menu.Portal>
</Menu.Root>Multiple triggers
Several triggers can open the same menu. Render more than one <Menu.Trigger> inside a single <Menu.Root>, or point several detached triggers at the same handle.
<Menu.Root>
<Menu.Trigger>Row actions</Menu.Trigger>
<Menu.Trigger>Quick actions</Menu.Trigger>
<!-- Rest of the menu -->
</Menu.Root><script>
const projectMenu = new Menu.Handle()
</script>
<Menu.Trigger handle={projectMenu}>Row actions</Menu.Trigger>
<Menu.Trigger handle={projectMenu}>Quick actions</Menu.Trigger>
<Menu.Root handle={projectMenu}>
<!-- Rest of the menu -->
</Menu.Root>A menu can show different content depending on which trigger opened it. Give each <Menu.Trigger> a payload prop and read it from the payload argument of <Menu.Root>'s children snippet (typed by the handle's type argument).
<script>
import { Menu } from '@shardsui/svelte/menu'
const menus = {
course: ['Rename', 'Duplicate', 'Archive'],
lesson: ['Add note', 'Bookmark', 'Share']
}
const demoMenu = new Menu.Handle<keyof typeof menus>()
</script>
<Menu.Trigger handle={demoMenu} payload={'course'}>Course</Menu.Trigger>
<Menu.Trigger handle={demoMenu} payload={'lesson'}>Lesson</Menu.Trigger>
<Menu.Root handle={demoMenu}>
{#snippet children({ payload })}
<Menu.Portal>
<Menu.Positioner>
<Menu.Popup>
<Menu.Viewport>
{#if payload}
{#each menus[payload] as item}
<Menu.Item>{item}</Menu.Item>
{/each}
{/if}
</Menu.Viewport>
</Menu.Popup>
</Menu.Positioner>
</Menu.Portal>
{/snippet}
</Menu.Root>Controlled mode with multiple triggers
Drive the open state yourself with open and onOpenChange on <Menu.Root>. With several triggers, track the active one through bind:triggerId on <Menu.Root> and a matching id on each <Menu.Trigger>: the binding follows whichever trigger opened the menu, and writing an id to it selects that trigger.
Arrow
<Menu.Arrow> renders an arrow inside the popup that points at the trigger.
Animating the Menu
When several detached triggers share one menu, you can animate its position, size, and content as it travels between them.
Position and Size
For position, transition the left, right, top, and bottom properties of the Positioner part. For size, transition the width and height of the Popup part.
Content
When different triggers swap what the menu shows, wrap the content in a <Menu.Viewport> to animate the change. It renders a div carrying data-activation-direction — space-separated horizontal (left or right) and vertical (up or down) values such as right down — so your animation can lean toward the direction of travel.
Within <Menu.Viewport>, each piece of content sits in a div tagged with a transition data attribute:
data-current: the content on screen when nothing is transitioning, or the incoming content during one.data-previous: the outgoing content during a transition.
API reference
Root
Groups all parts of the menu. Doesn't render its own HTML element.
Trigger
A button that opens the menu.
Renders a <button> element.
Backdrop
An overlay displayed beneath the popup.
Renders a <div> element.
Portal
A portal that moves the popup out to <body>, clear of ancestor clipping and stacking.
Renders a <div> element.
Positioner
Positions the menu popup against the trigger.
Renders a <div> element.
Popup
A container for the menu items.
Renders a <div> element.
Viewport
A viewport for displaying content transitions.
This component is only required if one popup can be opened by multiple triggers, its content
changes based on the trigger, and switching between them is animated.
Renders a <div> element.
Arrow
Displays an element positioned against the anchor.
Renders a <div> element.
Item
An individual interactive item in the menu.
Renders a <div> element.
LinkItem
A link in the menu that can be used to navigate to a different page or section.
Renders an <a> element.
SubmenuRoot
Groups all parts of a submenu. Doesn't render its own HTML element.
SubmenuTrigger
A menu item that opens a submenu.
Renders a <div> element.
Group
Groups related menu items with the corresponding label.
Renders a <div> element.
GroupLabel
An accessible label that is automatically associated with its parent group.
Renders a <div> element.
RadioGroup
Groups related radio items, labelled by a nested <Menu.GroupLabel>.
Renders a <div> element.
RadioItem
A menu item that works like a radio button in a given group.
Renders a <div> element.
RadioItemIndicator
Indicates whether the radio item is selected.
Renders a <span> element.
CheckboxItem
A menu item that toggles a setting on or off.
Renders a <div> element.
CheckboxItemIndicator
Indicates whether the checkbox item is ticked.
Renders a <span> element.
Separator
A separator element accessible to screen readers.
Renders a <div> element.
Handle
Connects a <Menu.Root> with detached <Menu.Trigger> components, and controls the menu imperatively. Pass a type argument to type the payload.
const menu = new Menu.Handle<Payload>()