3 Menu
L4stIdi0t edited this page 2026-10-01 17:34:52 +02:00

Menu

Accessible floating menu (APG menu): roving focus, ↑/↓/Home/End, Enter/ Space activate, Escape/Tab/click-outside close, focus returns to the opener.

Positioned at viewport (x, y) — works as a right-click context menu or an anchored dropdown. Built ourselves, matching Select/Tree in this lib.

Actions · two-way: bind:open · portalled to <body> · keyboard contract

<script lang="ts">
	import { Menu } from '@l4st/driftwood';
</script>
Light Dark
menu menu in dark mode

Props

Prop Type Default What it does
open bind: boolean false Bind it to open the menu yourself, from a click or a contextmenu event.
x number 0 Viewport coordinates of the menu's top-left (clamped on screen).
y number 0 Viewport coordinates of the top-left; clamped to stay on screen.
items required MenuItem[] — In render order. separatorBefore draws a divider above an item.
class string — Merged with the component's own classes, last — so yours win.

Types

export type MenuItem = {
	label: string;
	icon?: Component;
	/** Invoked on activation; receives the triggering event (read `shiftKey`). */
	onselect: (e: MouseEvent | KeyboardEvent) => void;
	disabled?: boolean;
	/** Render in the destructive color. */
	danger?: boolean;
	/** Trailing hint text (e.g. a shortcut or note). */
	hint?: string;
	/** Draw a divider above this item. */
	separatorBefore?: boolean;
};

Keyboard

Key Does
↑ / ↓ roving focus between items
Home / End first / last item
Enter / Space activate the focused item
Escape / Tab close, focus returns to the opener

Example

The markup behind the screenshot above, lifted from src/routes/shots/ — so it compiles, and it is exactly what produced the image.

<script lang="ts">
	import { Menu, Button, type MenuItem } from '$lib/index.js';
	import { MoreHorizontal, Pencil, Copy, Trash2 } from '@lucide/svelte';

	let open = $state(true);
	const items: MenuItem[] = [
		{ label: 'Rename', icon: Pencil, onselect: () => {} },
		{ label: 'Duplicate', icon: Copy, hint: '⌘D', onselect: () => {} },
		{ label: 'Delete', icon: Trash2, danger: true, separatorBefore: true, onselect: () => {} }
	];
</script>

<div class="p-8">
	<Button variant="outline" size="icon" aria-label="Row actions"><MoreHorizontal /></Button>
</div>
<Menu bind:open x={32} y={80} {items} />

Actions · Button · ButtonGroup · CopyButton · Toggle · ContextMenu


← All components · Getting started · Theming · source