Context Menu
Setup
Jhana UI uses a singleton Svelte component. You have to include this once in your root layout. Then you can use the context menu system across your whole app.
Global Menu
I like to have a single file that contains all context menus used by the app. However you can also write them specifically in those Svelte components or pages, where you actually need them.
Tag Map
You can also set up global behavior for specific element tags.
Binding to Elements
You've seen how you can set a global context menu, but of course you can bind one to any element. Left, center
and right specify the preferred alignment. Opening and closing animations originate at the attached element's
bottom midpoint for menus below, or its top midpoint for menus above. If the menu overlaps its source, it uses
the edge facing the menu's center. Pointer-positioned menus originate at the click position. That origin follows
the source even when the menu flips or shifts sideways near an edge. Menus keep at least var(--sideSpace) from every viewport edge, defaulting to var(--space-3) (1em). Panels that
fit neither below nor above their source shift upward just enough to clear the bottom edge, and long menus scroll
within that limit. A sideways shift preserves the vertical placement when it fits.
Custom Content
Beyond basic text, you can also provide a custom RenderingContent<CtxMenuItemProps>. This means { snippet: Snippet<[CtxMenuItemProps]> } | { component: Component<CtxMenuItemProps> }. Of
course, you can put any content inside, but this is how to do it, if you want it to look like the native context
menu. Your RenderingContent can contain multiple context menu entries. You wrap each one in a <li> and put a <button> inside – or multiple, if you want a horizontal button group. As long as you
wrap with <li>, everything is auto-styled for you. No need for any classes.
Settings content grows to its natural height. The menu keeps its viewport clearance and scrolls when the content no longer fits. Avoid an extra max-height such as 70dvh or an inner vertical scroller on the settings content: that makes dialogs scroll while usable viewport space remains.
Interactive Anchors
Edit the count, then click the plus button or right-click the input to reset it. The menu is centered on the whole box, keeping the input and its options together.
Attach a menu to a complete control group while keeping its inputs and buttons interactive. Right-clicking a child finds the nearest attached parent. A child button using openMenu with the same configuration anchors to that parent too. Without an attachment, openMenu anchors to the element whose handler runs, even when its icon or text is clicked. No synthetic events or pointer-event overrides are needed.
Inside Dialogs and Popovers
Keep one CtxMenuRoot in the app layout. Menus opened from a popup, native dialog or popover automatically join that layer so their controls remain interactive. Opening a menu keeps its parent popover open; Escape dismisses the menu before its parent. Closing or removing the parent also dismisses its menu. PopupRoot needs no children or additional menu root.
This popup reuses the boxed Copies toolbar above. Click its plus button or right-click the input, then choose Reset copies. The menu uses the popup's theme and viewport spacing.