Overlay
ContextMenu
Right-click context menu with icons, keyboard shortcuts, checkbox/radio items, submenus, and custom rendering.
Basic Usage
Right-click on the trigger area to open the menu.
vacation-photo.jpg
2.4 MB · Right-click me
<script lang="ts">
import { ContextMenu, Modal, Button } from 'sv5ui';
let showDeleteModal = $state(false);
const items = [
{ label: 'Edit', icon: 'lucide:pencil' },
{ label: 'Duplicate', icon: 'lucide:copy' },
{ label: 'Archive', icon: 'lucide:archive' },
{ label: 'Delete', icon: 'lucide:trash-2', color: 'error', onSelect: () => showDeleteModal = true }
];
</script>
<ContextMenu {items}>
<div class="rounded-xl border p-5">
<p class="font-medium">vacation-photo.jpg</p>
<p class="text-sm opacity-50">2.4 MB · Modified 2 days ago</p>
</div>
</ContextMenu>
<Modal
bind:open={showDeleteModal}
title="Delete file?"
description="This will permanently delete vacation-photo.jpg."
>
{#snippet footer()}
<div class="flex justify-end gap-2">
<Button variant="outline" color="surface" label="Cancel" onclick={() => showDeleteModal = false} />
<Button variant="solid" color="error" label="Delete" onclick={() => showDeleteModal = false} />
</div>
{/snippet}
</Modal>Keyboard Shortcuts
Show keyboard shortcuts with the kbds prop.
Text Editor
Right-click for editing shortcuts
<script lang="ts">
import { ContextMenu } from 'sv5ui';
const items = [
{ label: 'Undo', icon: 'lucide:undo-2', kbds: ['meta', 'z'] },
{ label: 'Redo', icon: 'lucide:redo-2', kbds: ['meta', 'shift', 'z'] },
{ type: 'separator' },
{ label: 'Cut', icon: 'lucide:scissors', kbds: ['meta', 'x'] },
{ label: 'Copy', icon: 'lucide:copy', kbds: ['meta', 'c'] },
{ label: 'Paste', icon: 'lucide:clipboard', kbds: ['meta', 'v'] }
];
</script>
<ContextMenu {items}>
<div class="rounded-xl border p-5">
<!-- Text editor area -->
Right-click to see editing shortcuts
</div>
</ContextMenu>Checkbox Items
Toggle options with type: 'checkbox'.
Canvas Workspace
Grid: On · Rulers: Off
<script lang="ts">
import { ContextMenu } from 'sv5ui';
let showGrid = $state(true);
let showRulers = $state(false);
let snapToGrid = $state(true);
let items = $derived([
{ type: 'label', label: 'View Options' },
{ type: 'separator' },
{ type: 'checkbox', label: 'Show Grid', checked: showGrid, closeOnSelect: false, onCheckedChange: (v) => showGrid = v },
{ type: 'checkbox', label: 'Show Rulers', checked: showRulers, closeOnSelect: false, onCheckedChange: (v) => showRulers = v },
{ type: 'checkbox', label: 'Snap to Grid', checked: snapToGrid, closeOnSelect: false, onCheckedChange: (v) => snapToGrid = v }
]);
</script>
<ContextMenu {items}>
<div class="rounded-xl border p-5">
<!-- Canvas workspace -->
</div>
</ContextMenu>Radio Items
Single-select with type: 'radio' and radioGroups.
File List
Sorted by: name
<script lang="ts">
import { ContextMenu } from 'sv5ui';
let sortBy = $state('name');
const items = [
{ type: 'label', label: 'Sort By' },
{ type: 'separator' },
{ type: 'radio', label: 'Name', value: 'name' },
{ type: 'radio', label: 'Date Modified', value: 'date' },
{ type: 'radio', label: 'Size', value: 'size' }
];
const radioGroups = [
{
name: 'sortBy',
value: sortBy,
onValueChange: (v) => sortBy = v
}
];
</script>
<ContextMenu {items} {radioGroups}>
<div class="rounded-xl border">
<!-- File list -->
</div>
</ContextMenu>Submenu
Nested menus with type: 'sub'.
Project Files
Right-click for actions
<script lang="ts">
import { ContextMenu } from 'sv5ui';
const items = [
{ label: 'New File', icon: 'lucide:file-plus' },
{ label: 'New Folder', icon: 'lucide:folder-plus' },
{ type: 'separator' },
{
type: 'sub',
label: 'Share',
icon: 'lucide:share-2',
items: [
{ label: 'Email', icon: 'lucide:mail' },
{ label: 'Message', icon: 'lucide:message-square' },
{ type: 'separator' },
{ label: 'More...', icon: 'lucide:more-horizontal' }
]
},
{ type: 'separator' },
{ label: 'Delete', icon: 'lucide:trash-2', color: 'error' }
];
</script>
<ContextMenu {items}>
<div class="rounded-xl border p-5">
<!-- Folder card -->
</div>
</ContextMenu>Sizes
5 menu sizes.
XS
SM
MD
LG
XL
<ContextMenu {items} size="xs">...</ContextMenu>
<ContextMenu {items} size="sm">...</ContextMenu>
<ContextMenu {items} size="md">...</ContextMenu>
<ContextMenu {items} size="lg">...</ContextMenu>
<ContextMenu {items} size="xl">...</ContextMenu>Disabled Items
Read-only Document
Some actions disabled
<script lang="ts">
import { ContextMenu } from 'sv5ui';
const items = [
{ label: 'Edit', icon: 'lucide:pencil' },
{ label: 'Duplicate', icon: 'lucide:copy', disabled: true },
{ label: 'Archive', icon: 'lucide:archive', disabled: true },
{ label: 'Delete', icon: 'lucide:trash-2', color: 'error' }
];
</script>
<ContextMenu {items}>
<div class="rounded-xl border p-5">
<!-- Read-only document -->
</div>
</ContextMenu>UI Slots
Use the ui prop to override classes on internal elements.
| Slot | Description |
|---|---|
content | Main context menu content area |
group | Item group container |
separator | Separator element |
label | Label/heading for groups |
item | Individual menu item |
itemLeadingIcon | Icon area before label |
itemLabel | Label text area |
itemTrailingKbds | Keyboard shortcut area |
itemIndicator | Checkbox/radio indicator |
subTrigger | Submenu trigger item |
subTriggerIcon | Submenu indicator icon |
subContent | Nested submenu content |
Snippets
| Snippet | Description |
|---|---|
children | Right-click trigger area (receives open state) |
header | Custom header content (receives close function) |
footer | Custom footer content (receives close function) |
item | Custom item rendering |
itemLeading | Custom leading section (icon area) |
itemLabel | Custom label section |
itemTrailing | Custom trailing section (kbd shortcuts) |
content | Replace entire items rendering |
Props
| Prop | Type | Default |
|---|---|---|
items | ContextMenuItem[] | - |
radioGroups | RadioGroup[] | - |
size | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'md' |
checkedIcon | string | 'lucide:check' |
submenuIcon | string | 'lucide:chevron-right' |
transition | boolean | true |
portal | boolean | true |
open | boolean | false |
ref | HTMLElement | null | null |
class | string | - |
ui | Record<Slot, Class> | - |