8.0k New

Context Menu

Displays a menu of actions triggered by a right click.

Docs API Reference

Epicenter

Local-first, open source apps

Special Sponsor
<script lang="ts">
  import * as ContextMenu from "$lib/components/ui/context-menu/index.js";
 
  let showBookmarks = $state(true);
  let showFullURLs = $state(false);
  let value = $state("pedro");
</script>
 
<ContextMenu.Root>
  <ContextMenu.Trigger
    class="flex aspect-video w-full max-w-xs items-center justify-center rounded-xl border border-dashed text-sm"
  >
    <span class="hidden pointer-fine:inline-block">Right click here</span>
    <span class="hidden pointer-coarse:inline-block">Long press here</span>
  </ContextMenu.Trigger>
  <ContextMenu.Content class="w-48">
    <ContextMenu.Group>
      <ContextMenu.Item>
        Back
        <ContextMenu.Shortcut>⌘[</ContextMenu.Shortcut>
      </ContextMenu.Item>
      <ContextMenu.Item disabled>
        Forward
        <ContextMenu.Shortcut>⌘]</ContextMenu.Shortcut>
      </ContextMenu.Item>
      <ContextMenu.Item>
        Reload
        <ContextMenu.Shortcut>⌘R</ContextMenu.Shortcut>
      </ContextMenu.Item>
      <ContextMenu.Sub>
        <ContextMenu.SubTrigger>More Tools</ContextMenu.SubTrigger>
        <ContextMenu.SubContent class="w-44">
          <ContextMenu.Group>
            <ContextMenu.Item>Save Page...</ContextMenu.Item>
            <ContextMenu.Item>Create Shortcut...</ContextMenu.Item>
            <ContextMenu.Item>Name Window...</ContextMenu.Item>
          </ContextMenu.Group>
          <ContextMenu.Separator />
          <ContextMenu.Group>
            <ContextMenu.Item>Developer Tools</ContextMenu.Item>
          </ContextMenu.Group>
          <ContextMenu.Separator />
          <ContextMenu.Group>
            <ContextMenu.Item variant="destructive">Delete</ContextMenu.Item>
          </ContextMenu.Group>
        </ContextMenu.SubContent>
      </ContextMenu.Sub>
    </ContextMenu.Group>
    <ContextMenu.Separator />
    <ContextMenu.Group>
      <ContextMenu.CheckboxItem bind:checked={showBookmarks}
        >Show Bookmarks</ContextMenu.CheckboxItem
      >
      <ContextMenu.CheckboxItem bind:checked={showFullURLs}
        >Show Full URLs</ContextMenu.CheckboxItem
      >
    </ContextMenu.Group>
    <ContextMenu.Separator />
    <ContextMenu.Group>
      <ContextMenu.RadioGroup bind:value>
        <ContextMenu.Label>People</ContextMenu.Label>
        <ContextMenu.RadioItem value="pedro">Pedro Duarte</ContextMenu.RadioItem
        >
        <ContextMenu.RadioItem value="colm">Colm Tuite</ContextMenu.RadioItem>
      </ContextMenu.RadioGroup>
    </ContextMenu.Group>
  </ContextMenu.Content>
</ContextMenu.Root>

Installation

pnpm dlx shadcn-svelte@latest add context-menu

Usage

<script lang="ts">
  import * as ContextMenu from "$lib/components/ui/context-menu/index.js";
</script>
<ContextMenu.Root>
  <ContextMenu.Trigger>Right click here</ContextMenu.Trigger>
  <ContextMenu.Content>
    <ContextMenu.Item>Profile</ContextMenu.Item>
    <ContextMenu.Item>Billing</ContextMenu.Item>
    <ContextMenu.Item>Team</ContextMenu.Item>
    <ContextMenu.Item>Subscription</ContextMenu.Item>
  </ContextMenu.Content>
</ContextMenu.Root>

Basic

A simple context menu with a few actions.

<script lang="ts">
  import * as ContextMenu from "$lib/components/ui/context-menu/index.js";
</script>
 
<ContextMenu.Root>
  <ContextMenu.Trigger
    class="flex aspect-video w-full max-w-xs items-center justify-center rounded-xl border border-dashed text-sm"
  >
    <span class="hidden pointer-fine:inline-block">Right click here</span>
    <span class="hidden pointer-coarse:inline-block">Long press here</span>
  </ContextMenu.Trigger>
  <ContextMenu.Content>
    <ContextMenu.Group>
      <ContextMenu.Item>Back</ContextMenu.Item>
      <ContextMenu.Item disabled>Forward</ContextMenu.Item>
      <ContextMenu.Item>Reload</ContextMenu.Item>
    </ContextMenu.Group>
  </ContextMenu.Content>
</ContextMenu.Root>

Use ContextMenu.Sub to nest secondary actions.

<script lang="ts">
  import * as ContextMenu from "$lib/components/ui/context-menu/index.js";
</script>
 
<ContextMenu.Root>
  <ContextMenu.Trigger
    class="flex aspect-video w-full max-w-xs items-center justify-center rounded-xl border border-dashed text-sm"
  >
    <span class="hidden pointer-fine:inline-block">Right click here</span>
    <span class="hidden pointer-coarse:inline-block">Long press here</span>
  </ContextMenu.Trigger>
  <ContextMenu.Content>
    <ContextMenu.Group>
      <ContextMenu.Item>
        Copy
        <ContextMenu.Shortcut>⌘C</ContextMenu.Shortcut>
      </ContextMenu.Item>
      <ContextMenu.Item>
        Cut
        <ContextMenu.Shortcut>⌘X</ContextMenu.Shortcut>
      </ContextMenu.Item>
    </ContextMenu.Group>
    <ContextMenu.Sub>
      <ContextMenu.SubTrigger>More Tools</ContextMenu.SubTrigger>
      <ContextMenu.SubContent>
        <ContextMenu.Group>
          <ContextMenu.Item>Save Page...</ContextMenu.Item>
          <ContextMenu.Item>Create Shortcut...</ContextMenu.Item>
          <ContextMenu.Item>Name Window...</ContextMenu.Item>
        </ContextMenu.Group>
        <ContextMenu.Separator />
        <ContextMenu.Group>
          <ContextMenu.Item>Developer Tools</ContextMenu.Item>
        </ContextMenu.Group>
        <ContextMenu.Separator />
        <ContextMenu.Group>
          <ContextMenu.Item variant="destructive">Delete</ContextMenu.Item>
        </ContextMenu.Group>
      </ContextMenu.SubContent>
    </ContextMenu.Sub>
  </ContextMenu.Content>
</ContextMenu.Root>

Shortcuts

Add ContextMenu.Shortcut to show keyboard hints.

<script lang="ts">
  import * as ContextMenu from "$lib/components/ui/context-menu/index.js";
</script>
 
<ContextMenu.Root>
  <ContextMenu.Trigger
    class="flex aspect-video w-full max-w-xs items-center justify-center rounded-xl border border-dashed text-sm"
  >
    <span class="hidden pointer-fine:inline-block">Right click here</span>
    <span class="hidden pointer-coarse:inline-block">Long press here</span>
  </ContextMenu.Trigger>
  <ContextMenu.Content>
    <ContextMenu.Group>
      <ContextMenu.Item>
        Back
        <ContextMenu.Shortcut>⌘[</ContextMenu.Shortcut>
      </ContextMenu.Item>
      <ContextMenu.Item disabled>
        Forward
        <ContextMenu.Shortcut>⌘]</ContextMenu.Shortcut>
      </ContextMenu.Item>
      <ContextMenu.Item>
        Reload
        <ContextMenu.Shortcut>⌘R</ContextMenu.Shortcut>
      </ContextMenu.Item>
    </ContextMenu.Group>
    <ContextMenu.Separator />
    <ContextMenu.Group>
      <ContextMenu.Item>
        Save
        <ContextMenu.Shortcut>⌘S</ContextMenu.Shortcut>
      </ContextMenu.Item>
      <ContextMenu.Item>
        Save As...
        <ContextMenu.Shortcut>⇧⌘S</ContextMenu.Shortcut>
      </ContextMenu.Item>
    </ContextMenu.Group>
  </ContextMenu.Content>
</ContextMenu.Root>

Groups

Group related actions and separate them with dividers.

<script lang="ts">
  import * as ContextMenu from "$lib/components/ui/context-menu/index.js";
</script>
 
<ContextMenu.Root>
  <ContextMenu.Trigger
    class="flex aspect-video w-full max-w-xs items-center justify-center rounded-xl border border-dashed text-sm"
  >
    <span class="hidden pointer-fine:inline-block">Right click here</span>
    <span class="hidden pointer-coarse:inline-block">Long press here</span>
  </ContextMenu.Trigger>
  <ContextMenu.Content>
    <ContextMenu.Group>
      <ContextMenu.Label>File</ContextMenu.Label>
      <ContextMenu.Item>
        New File
        <ContextMenu.Shortcut>⌘N</ContextMenu.Shortcut>
      </ContextMenu.Item>
      <ContextMenu.Item>
        Open File
        <ContextMenu.Shortcut>⌘O</ContextMenu.Shortcut>
      </ContextMenu.Item>
      <ContextMenu.Item>
        Save
        <ContextMenu.Shortcut>⌘S</ContextMenu.Shortcut>
      </ContextMenu.Item>
    </ContextMenu.Group>
    <ContextMenu.Separator />
    <ContextMenu.Group>
      <ContextMenu.Label>Edit</ContextMenu.Label>
      <ContextMenu.Item>
        Undo
        <ContextMenu.Shortcut>⌘Z</ContextMenu.Shortcut>
      </ContextMenu.Item>
      <ContextMenu.Item>
        Redo
        <ContextMenu.Shortcut>⇧⌘Z</ContextMenu.Shortcut>
      </ContextMenu.Item>
    </ContextMenu.Group>
    <ContextMenu.Separator />
    <ContextMenu.Group>
      <ContextMenu.Item>
        Cut
        <ContextMenu.Shortcut>⌘X</ContextMenu.Shortcut>
      </ContextMenu.Item>
      <ContextMenu.Item>
        Copy
        <ContextMenu.Shortcut>⌘C</ContextMenu.Shortcut>
      </ContextMenu.Item>
      <ContextMenu.Item>
        Paste
        <ContextMenu.Shortcut>⌘V</ContextMenu.Shortcut>
      </ContextMenu.Item>
    </ContextMenu.Group>
    <ContextMenu.Separator />
    <ContextMenu.Group>
      <ContextMenu.Item variant="destructive">
        Delete
        <ContextMenu.Shortcut>⌫</ContextMenu.Shortcut>
      </ContextMenu.Item>
    </ContextMenu.Group>
  </ContextMenu.Content>
</ContextMenu.Root>

Icons

Combine icons with labels for quick scanning.

<script lang="ts">
  import ClipboardPasteIcon from "@lucide/svelte/icons/clipboard-paste";
  import CopyIcon from "@lucide/svelte/icons/copy";
  import ScissorsIcon from "@lucide/svelte/icons/scissors";
  import TrashIcon from "@lucide/svelte/icons/trash";
  import * as ContextMenu from "$lib/components/ui/context-menu/index.js";
</script>
 
<ContextMenu.Root>
  <ContextMenu.Trigger
    class="flex aspect-video w-full max-w-xs items-center justify-center rounded-xl border border-dashed text-sm"
  >
    <span class="hidden pointer-fine:inline-block">Right click here</span>
    <span class="hidden pointer-coarse:inline-block">Long press here</span>
  </ContextMenu.Trigger>
  <ContextMenu.Content>
    <ContextMenu.Group>
      <ContextMenu.Item>
        <CopyIcon />
        Copy
      </ContextMenu.Item>
      <ContextMenu.Item>
        <ScissorsIcon />
        Cut
      </ContextMenu.Item>
      <ContextMenu.Item>
        <ClipboardPasteIcon />
        Paste
      </ContextMenu.Item>
    </ContextMenu.Group>
    <ContextMenu.Separator />
    <ContextMenu.Group>
      <ContextMenu.Item variant="destructive">
        <TrashIcon />
        Delete
      </ContextMenu.Item>
    </ContextMenu.Group>
  </ContextMenu.Content>
</ContextMenu.Root>

Checkboxes

Use ContextMenu.CheckboxItem for toggles.

<script lang="ts">
  import * as ContextMenu from "$lib/components/ui/context-menu/index.js";
 
  let showBookmarksBar = $state(true);
  let showFullURLs = $state(false);
  let showDeveloperTools = $state(true);
</script>
 
<ContextMenu.Root>
  <ContextMenu.Trigger
    class="flex aspect-video w-full max-w-xs items-center justify-center rounded-xl border border-dashed text-sm"
  >
    <span class="hidden pointer-fine:inline-block">Right click here</span>
    <span class="hidden pointer-coarse:inline-block">Long press here</span>
  </ContextMenu.Trigger>
  <ContextMenu.Content>
    <ContextMenu.Group>
      <ContextMenu.CheckboxItem bind:checked={showBookmarksBar}>
        Show Bookmarks Bar
      </ContextMenu.CheckboxItem>
      <ContextMenu.CheckboxItem bind:checked={showFullURLs}
        >Show Full URLs</ContextMenu.CheckboxItem
      >
      <ContextMenu.CheckboxItem bind:checked={showDeveloperTools}>
        Show Developer Tools
      </ContextMenu.CheckboxItem>
    </ContextMenu.Group>
  </ContextMenu.Content>
</ContextMenu.Root>

Radio

Use ContextMenu.RadioItem for exclusive choices.

<script lang="ts">
  import * as ContextMenu from "$lib/components/ui/context-menu/index.js";
 
  let user = $state("pedro");
  let theme = $state("light");
</script>
 
<ContextMenu.Root>
  <ContextMenu.Trigger
    class="flex aspect-video w-full max-w-xs items-center justify-center rounded-xl border border-dashed text-sm"
  >
    <span class="hidden pointer-fine:inline-block">Right click here</span>
    <span class="hidden pointer-coarse:inline-block">Long press here</span>
  </ContextMenu.Trigger>
  <ContextMenu.Content>
    <ContextMenu.Group>
      <ContextMenu.Label>People</ContextMenu.Label>
      <ContextMenu.RadioGroup bind:value={user}>
        <ContextMenu.RadioItem value="pedro">Pedro Duarte</ContextMenu.RadioItem
        >
        <ContextMenu.RadioItem value="colm">Colm Tuite</ContextMenu.RadioItem>
      </ContextMenu.RadioGroup>
    </ContextMenu.Group>
    <ContextMenu.Separator />
    <ContextMenu.Group>
      <ContextMenu.Label>Theme</ContextMenu.Label>
      <ContextMenu.RadioGroup bind:value={theme}>
        <ContextMenu.RadioItem value="light">Light</ContextMenu.RadioItem>
        <ContextMenu.RadioItem value="dark">Dark</ContextMenu.RadioItem>
        <ContextMenu.RadioItem value="system">System</ContextMenu.RadioItem>
      </ContextMenu.RadioGroup>
    </ContextMenu.Group>
  </ContextMenu.Content>
</ContextMenu.Root>

Destructive

Use variant="destructive" to style the menu item as destructive.

<script lang="ts">
  import PencilIcon from "@lucide/svelte/icons/pencil";
  import ShareIcon from "@lucide/svelte/icons/share";
  import TrashIcon from "@lucide/svelte/icons/trash";
  import * as ContextMenu from "$lib/components/ui/context-menu/index.js";
</script>
 
<ContextMenu.Root>
  <ContextMenu.Trigger
    class="flex aspect-video w-full max-w-xs items-center justify-center rounded-xl border border-dashed text-sm"
  >
    <span class="hidden pointer-fine:inline-block">Right click here</span>
    <span class="hidden pointer-coarse:inline-block">Long press here</span>
  </ContextMenu.Trigger>
  <ContextMenu.Content>
    <ContextMenu.Group>
      <ContextMenu.Item>
        <PencilIcon />
        Edit
      </ContextMenu.Item>
      <ContextMenu.Item>
        <ShareIcon />
        Share
      </ContextMenu.Item>
    </ContextMenu.Group>
    <ContextMenu.Separator />
    <ContextMenu.Group>
      <ContextMenu.Item variant="destructive">
        <TrashIcon />
        Delete
      </ContextMenu.Item>
    </ContextMenu.Group>
  </ContextMenu.Content>
</ContextMenu.Root>

Sides

Control submenu placement with side and align props.

<script lang="ts">
  import * as ContextMenu from "$lib/components/ui/context-menu/index.js";
 
  const sides = ["top", "right", "bottom", "left"] as const;
</script>
 
<div class="grid w-full max-w-sm grid-cols-2 gap-4">
  {#each sides as side (side)}
    <ContextMenu.Root>
      <ContextMenu.Trigger
        class="flex aspect-video w-full max-w-xs items-center justify-center rounded-xl border border-dashed text-sm"
      >
        <span class="hidden pointer-fine:inline-block"
          >Right click ({side})</span
        >
        <span class="hidden pointer-coarse:inline-block"
          >Long press ({side})</span
        >
      </ContextMenu.Trigger>
      <ContextMenu.Content {side}>
        <ContextMenu.Group>
          <ContextMenu.Item>Back</ContextMenu.Item>
          <ContextMenu.Item>Forward</ContextMenu.Item>
          <ContextMenu.Item>Reload</ContextMenu.Item>
        </ContextMenu.Group>
      </ContextMenu.Content>
    </ContextMenu.Root>
  {/each}
</div>