Context Menu
Displays a menu of actions triggered by a right click.
The Context Menu component is built on top of Kobalte Context Menu, which provides accessible context-menu, keyboard, and focus behavior.
import { ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger,} from "~/components/ui/context-menu";
export default function ContextMenuDemo() { return ( <ContextMenu> <ContextMenuTrigger class="flex aspect-video w-full max-w-xs items-center justify-center rounded-xl border border-dashed text-sm"> <span class="pointer-fine:inline-block hidden">Right click here</span> <span class="pointer-coarse:inline-block hidden">Long press here</span> </ContextMenuTrigger> <ContextMenuContent class="w-48"> <ContextMenuGroup> <ContextMenuItem> Back<ContextMenuShortcut>⌘[</ContextMenuShortcut> </ContextMenuItem> <ContextMenuItem disabled> Forward<ContextMenuShortcut>⌘]</ContextMenuShortcut> </ContextMenuItem> <ContextMenuItem> Reload<ContextMenuShortcut>⌘R</ContextMenuShortcut> </ContextMenuItem> <ContextMenuSub> <ContextMenuSubTrigger>More Tools</ContextMenuSubTrigger> <ContextMenuSubContent class="w-44"> <ContextMenuGroup> <ContextMenuItem>Save Page...</ContextMenuItem> <ContextMenuItem>Create Shortcut...</ContextMenuItem> <ContextMenuItem>Name Window...</ContextMenuItem> </ContextMenuGroup> <ContextMenuSeparator /> <ContextMenuItem>Developer Tools</ContextMenuItem> <ContextMenuSeparator /> <ContextMenuItem variant="destructive">Delete</ContextMenuItem> </ContextMenuSubContent> </ContextMenuSub> </ContextMenuGroup> <ContextMenuSeparator /> <ContextMenuGroup> <ContextMenuCheckboxItem checked>Show Bookmarks</ContextMenuCheckboxItem> <ContextMenuCheckboxItem>Show Full URLs</ContextMenuCheckboxItem> </ContextMenuGroup> <ContextMenuSeparator /> <ContextMenuGroup> <ContextMenuRadioGroup value="pedro"> <ContextMenuLabel>People</ContextMenuLabel> <ContextMenuRadioItem value="pedro">Pedro Duarte</ContextMenuRadioItem> <ContextMenuRadioItem value="colm">Colm Tuite</ContextMenuRadioItem> </ContextMenuRadioGroup> </ContextMenuGroup> </ContextMenuContent> </ContextMenu> );}Installation
Usage
import { ContextMenu, ContextMenuContent, ContextMenuItem, ContextMenuTrigger,} from "~/components/ui/context-menu";<ContextMenu> <ContextMenuTrigger>Right click here</ContextMenuTrigger> <ContextMenuContent> <ContextMenuItem>Profile</ContextMenuItem> <ContextMenuItem>Billing</ContextMenuItem> <ContextMenuItem>Team</ContextMenuItem> <ContextMenuItem>Subscription</ContextMenuItem> </ContextMenuContent></ContextMenu>See the Kobalte Context Menu documentation for primitive-level options, accessibility, and keyboard behavior.
Composition
Use the following composition to build a ContextMenu:
ContextMenu├── ContextMenuTrigger└── ContextMenuContent ├── ContextMenuGroup │ ├── ContextMenuLabel │ ├── ContextMenuItem │ └── ContextMenuItem ├── ContextMenuSeparator ├── ContextMenuGroup │ ├── ContextMenuLabel │ ├── ContextMenuCheckboxItem │ └── ContextMenuCheckboxItem ├── ContextMenuSeparator ├── ContextMenuGroup │ ├── ContextMenuLabel │ └── ContextMenuRadioGroup │ ├── ContextMenuRadioItem │ └── ContextMenuRadioItem └── ContextMenuSub ├── ContextMenuSubTrigger └── ContextMenuSubContent └── ContextMenuGroup ├── ContextMenuItem └── ContextMenuItemBasic
A simple context menu with a few actions.
import { ContextMenu, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuTrigger,} from "~/components/ui/context-menu";
export default function ContextMenuBasic() { return ( <ContextMenu> <ContextMenuTrigger class="flex aspect-video w-full max-w-xs items-center justify-center rounded-xl border border-dashed text-sm"> <span class="pointer-fine:inline-block hidden">Right click here</span> <span class="pointer-coarse:inline-block hidden">Long press here</span> </ContextMenuTrigger> <ContextMenuContent> <ContextMenuGroup> <ContextMenuItem>Back</ContextMenuItem> <ContextMenuItem disabled>Forward</ContextMenuItem> <ContextMenuItem>Reload</ContextMenuItem> </ContextMenuGroup> </ContextMenuContent> </ContextMenu> );}Submenu
Use ContextMenuSub to nest secondary actions.
import { ContextMenu, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger,} from "~/components/ui/context-menu";
export default function ContextMenuSubmenu() { return ( <ContextMenu> <ContextMenuTrigger class="flex aspect-video w-full max-w-xs items-center justify-center rounded-xl border border-dashed text-sm"> <span class="pointer-fine:inline-block hidden">Right click here</span> <span class="pointer-coarse:inline-block hidden">Long press here</span> </ContextMenuTrigger> <ContextMenuContent> <ContextMenuGroup> <ContextMenuItem> Copy<ContextMenuShortcut>⌘C</ContextMenuShortcut> </ContextMenuItem> <ContextMenuItem> Cut<ContextMenuShortcut>⌘X</ContextMenuShortcut> </ContextMenuItem> </ContextMenuGroup> <ContextMenuSub> <ContextMenuSubTrigger>More Tools</ContextMenuSubTrigger> <ContextMenuSubContent> <ContextMenuGroup> <ContextMenuItem>Save Page...</ContextMenuItem> <ContextMenuItem>Create Shortcut...</ContextMenuItem> <ContextMenuItem>Name Window...</ContextMenuItem> </ContextMenuGroup> <ContextMenuSeparator /> <ContextMenuItem>Developer Tools</ContextMenuItem> <ContextMenuSeparator /> <ContextMenuItem variant="destructive">Delete</ContextMenuItem> </ContextMenuSubContent> </ContextMenuSub> </ContextMenuContent> </ContextMenu> );}Shortcuts
Add ContextMenuShortcut to show keyboard hints.
import { ContextMenu, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuTrigger,} from "~/components/ui/context-menu";
export default function ContextMenuShortcuts() { return ( <ContextMenu> <ContextMenuTrigger class="flex aspect-video w-full max-w-xs items-center justify-center rounded-xl border border-dashed text-sm"> <span class="pointer-fine:inline-block hidden">Right click here</span> <span class="pointer-coarse:inline-block hidden">Long press here</span> </ContextMenuTrigger> <ContextMenuContent> <ContextMenuGroup> <ContextMenuItem> Back<ContextMenuShortcut>⌘[</ContextMenuShortcut> </ContextMenuItem> <ContextMenuItem disabled> Forward<ContextMenuShortcut>⌘]</ContextMenuShortcut> </ContextMenuItem> <ContextMenuItem> Reload<ContextMenuShortcut>⌘R</ContextMenuShortcut> </ContextMenuItem> </ContextMenuGroup> <ContextMenuSeparator /> <ContextMenuGroup> <ContextMenuItem> Save<ContextMenuShortcut>⌘S</ContextMenuShortcut> </ContextMenuItem> <ContextMenuItem> Save As...<ContextMenuShortcut>⇧⌘S</ContextMenuShortcut> </ContextMenuItem> </ContextMenuGroup> </ContextMenuContent> </ContextMenu> );}Groups
Group related actions and separate them with dividers.
import { ContextMenu, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuSeparator, ContextMenuShortcut, ContextMenuTrigger,} from "~/components/ui/context-menu";
export default function ContextMenuGroups() { return ( <ContextMenu> <ContextMenuTrigger class="flex aspect-video w-full max-w-xs items-center justify-center rounded-xl border border-dashed text-sm"> <span class="pointer-fine:inline-block hidden">Right click here</span> <span class="pointer-coarse:inline-block hidden">Long press here</span> </ContextMenuTrigger> <ContextMenuContent> <ContextMenuGroup> <ContextMenuLabel>File</ContextMenuLabel> <ContextMenuItem> New File<ContextMenuShortcut>⌘N</ContextMenuShortcut> </ContextMenuItem> <ContextMenuItem> Open File<ContextMenuShortcut>⌘O</ContextMenuShortcut> </ContextMenuItem> <ContextMenuItem> Save<ContextMenuShortcut>⌘S</ContextMenuShortcut> </ContextMenuItem> </ContextMenuGroup> <ContextMenuSeparator /> <ContextMenuGroup> <ContextMenuLabel>Edit</ContextMenuLabel> <ContextMenuItem> Undo<ContextMenuShortcut>⌘Z</ContextMenuShortcut> </ContextMenuItem> <ContextMenuItem> Redo<ContextMenuShortcut>⇧⌘Z</ContextMenuShortcut> </ContextMenuItem> </ContextMenuGroup> <ContextMenuSeparator /> <ContextMenuGroup> <ContextMenuItem> Cut<ContextMenuShortcut>⌘X</ContextMenuShortcut> </ContextMenuItem> <ContextMenuItem> Copy<ContextMenuShortcut>⌘C</ContextMenuShortcut> </ContextMenuItem> <ContextMenuItem> Paste<ContextMenuShortcut>⌘V</ContextMenuShortcut> </ContextMenuItem> </ContextMenuGroup> <ContextMenuSeparator /> <ContextMenuItem variant="destructive"> Delete<ContextMenuShortcut>⌫</ContextMenuShortcut> </ContextMenuItem> </ContextMenuContent> </ContextMenu> );}Icons
Combine icons with labels for quick scanning.
import { ClipboardPasteIcon, CopyIcon, ScissorsIcon, TrashIcon } from "lucide-solid";import { ContextMenu, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuSeparator, ContextMenuTrigger,} from "~/components/ui/context-menu";
export default function ContextMenuIcons() { return ( <ContextMenu> <ContextMenuTrigger class="flex aspect-video w-full max-w-xs items-center justify-center rounded-xl border border-dashed text-sm"> <span class="pointer-fine:inline-block hidden">Right click here</span> <span class="pointer-coarse:inline-block hidden">Long press here</span> </ContextMenuTrigger> <ContextMenuContent> <ContextMenuGroup> <ContextMenuItem> <CopyIcon /> Copy </ContextMenuItem> <ContextMenuItem> <ScissorsIcon /> Cut </ContextMenuItem> <ContextMenuItem> <ClipboardPasteIcon /> Paste </ContextMenuItem> </ContextMenuGroup> <ContextMenuSeparator /> <ContextMenuItem variant="destructive"> <TrashIcon /> Delete </ContextMenuItem> </ContextMenuContent> </ContextMenu> );}Checkboxes
Use ContextMenuCheckboxItem for toggles.
import { ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuTrigger,} from "~/components/ui/context-menu";
export default function ContextMenuCheckboxes() { return ( <ContextMenu> <ContextMenuTrigger class="flex aspect-video w-full max-w-xs items-center justify-center rounded-xl border border-dashed text-sm"> <span class="pointer-fine:inline-block hidden">Right click here</span> <span class="pointer-coarse:inline-block hidden">Long press here</span> </ContextMenuTrigger> <ContextMenuContent> <ContextMenuGroup> <ContextMenuCheckboxItem defaultChecked>Show Bookmarks Bar</ContextMenuCheckboxItem> <ContextMenuCheckboxItem>Show Full URLs</ContextMenuCheckboxItem> <ContextMenuCheckboxItem defaultChecked>Show Developer Tools</ContextMenuCheckboxItem> </ContextMenuGroup> </ContextMenuContent> </ContextMenu> );}Radio
Use ContextMenuRadioItem for exclusive choices.
import { createSignal } from "solid-js";import { ContextMenu, ContextMenuContent, ContextMenuGroup, ContextMenuLabel, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuTrigger,} from "~/components/ui/context-menu";
export default function ContextMenuRadio() { const [user, setUser] = createSignal("pedro"); const [theme, setTheme] = createSignal("light");
return ( <ContextMenu> <ContextMenuTrigger class="flex aspect-video w-full max-w-xs items-center justify-center rounded-xl border border-dashed text-sm"> <span class="pointer-fine:inline-block hidden">Right click here</span> <span class="pointer-coarse:inline-block hidden">Long press here</span> </ContextMenuTrigger> <ContextMenuContent> <ContextMenuGroup> <ContextMenuLabel>People</ContextMenuLabel> <ContextMenuRadioGroup value={user()} onChange={(value) => setUser(value)}> <ContextMenuRadioItem value="pedro">Pedro Duarte</ContextMenuRadioItem> <ContextMenuRadioItem value="colm">Colm Tuite</ContextMenuRadioItem> </ContextMenuRadioGroup> </ContextMenuGroup> <ContextMenuSeparator /> <ContextMenuGroup> <ContextMenuLabel>Theme</ContextMenuLabel> <ContextMenuRadioGroup value={theme()} onChange={(value) => setTheme(value)}> <ContextMenuRadioItem value="light">Light</ContextMenuRadioItem> <ContextMenuRadioItem value="dark">Dark</ContextMenuRadioItem> <ContextMenuRadioItem value="system">System</ContextMenuRadioItem> </ContextMenuRadioGroup> </ContextMenuGroup> </ContextMenuContent> </ContextMenu> );}Destructive
Use variant="destructive" to style the menu item as destructive.
import { PencilIcon, ShareIcon, TrashIcon } from "lucide-solid";import { ContextMenu, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuSeparator, ContextMenuTrigger,} from "~/components/ui/context-menu";
export default function ContextMenuDestructive() { return ( <ContextMenu> <ContextMenuTrigger class="flex aspect-video w-full max-w-xs items-center justify-center rounded-xl border border-dashed text-sm"> <span class="pointer-fine:inline-block hidden">Right click here</span> <span class="pointer-coarse:inline-block hidden">Long press here</span> </ContextMenuTrigger> <ContextMenuContent> <ContextMenuGroup> <ContextMenuItem> <PencilIcon /> Edit </ContextMenuItem> <ContextMenuItem> <ShareIcon /> Share </ContextMenuItem> </ContextMenuGroup> <ContextMenuSeparator /> <ContextMenuItem variant="destructive"> <TrashIcon /> Delete </ContextMenuItem> </ContextMenuContent> </ContextMenu> );}Sides
Control menu placement by passing a placement prop to ContextMenu.
import { For } from "solid-js";import { ContextMenu, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuTrigger,} from "~/components/ui/context-menu";
const sides = ["top", "right", "bottom", "left"] as const;
export default function ContextMenuSides() { return ( <div class="grid w-full max-w-sm grid-cols-2 gap-4"> <For each={sides}> {(side) => ( <ContextMenu placement={side}> <ContextMenuTrigger class="flex aspect-video w-full max-w-xs items-center justify-center rounded-xl border border-dashed text-sm"> <span class="pointer-fine:inline-block hidden">Right click ({side})</span> <span class="pointer-coarse:inline-block hidden">Long press ({side})</span> </ContextMenuTrigger> <ContextMenuContent> <ContextMenuGroup> <ContextMenuItem>Back</ContextMenuItem> <ContextMenuItem>Forward</ContextMenuItem> <ContextMenuItem>Reload</ContextMenuItem> </ContextMenuGroup> </ContextMenuContent> </ContextMenu> )} </For> </div> );}API Reference
See the Kobalte Context Menu API reference for primitive props, keyboard behavior, and accessibility details.