Components

Base Components

Context Menu

A menu that appears on right-click or long-press for contextual actions.

Example

Right click here

Installation

Install the following dependencies:

npm install radix-uinpm install lucide-react

Create a context-menu.tsx file and paste the following code into it.

"use client"import * as React from "react"import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react"import { ContextMenu as ContextMenuPrimitive } from "radix-ui"import { cn } from "@/lib/utils"function ContextMenu({  ...props}: React.ComponentProps<typeof ContextMenuPrimitive.Root>) {  return <ContextMenuPrimitive.Root data-slot="context-menu" {...props} />}function ContextMenuTrigger({  ...props}: React.ComponentProps<typeof ContextMenuPrimitive.Trigger>) {  return (    <ContextMenuPrimitive.Trigger data-slot="context-menu-trigger" {...props} />  )}function ContextMenuGroup({  ...props}: React.ComponentProps<typeof ContextMenuPrimitive.Group>) {  return (    <ContextMenuPrimitive.Group data-slot="context-menu-group" {...props} />  )}function ContextMenuPortal({  ...props}: React.ComponentProps<typeof ContextMenuPrimitive.Portal>) {  return (    <ContextMenuPrimitive.Portal data-slot="context-menu-portal" {...props} />  )}function ContextMenuSub({  ...props}: React.ComponentProps<typeof ContextMenuPrimitive.Sub>) {  return <ContextMenuPrimitive.Sub data-slot="context-menu-sub" {...props} />}function ContextMenuRadioGroup({  ...props}: React.ComponentProps<typeof ContextMenuPrimitive.RadioGroup>) {  return (    <ContextMenuPrimitive.RadioGroup      data-slot="context-menu-radio-group"      {...props}    />  )}function ContextMenuSubTrigger({  className,  inset,  children,  ...props}: React.ComponentProps<typeof ContextMenuPrimitive.SubTrigger> & {  inset?: boolean}) {  return (    <ContextMenuPrimitive.SubTrigger      data-slot="context-menu-sub-trigger"      data-inset={inset}      className={cn(        "text-primary focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground [&_svg:not([class*='text-'])]:text-primary flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",        className      )}      {...props}    >      {children}      <ChevronRightIcon className="ml-auto" />    </ContextMenuPrimitive.SubTrigger>  )}function ContextMenuSubContent({  className,  ...props}: React.ComponentProps<typeof ContextMenuPrimitive.SubContent>) {  return (    <ContextMenuPrimitive.SubContent      data-slot="context-menu-sub-content"      className={cn(        "bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[8rem] origin-(--radix-context-menu-content-transform-origin) overflow-hidden rounded-md border p-1 shadow-lg",        className      )}      {...props}    />  )}function ContextMenuContent({  className,  ...props}: React.ComponentProps<typeof ContextMenuPrimitive.Content> & {  dir?: React.HTMLAttributes<HTMLDivElement>["dir"]}) {  return (    <ContextMenuPrimitive.Portal>      <ContextMenuPrimitive.Content        data-slot="context-menu-content"        className={cn(          "bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 max-h-(--radix-context-menu-content-available-height) min-w-[8rem] origin-(--radix-context-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border p-1 shadow-md",          className        )}        {...props}      />    </ContextMenuPrimitive.Portal>  )}function ContextMenuItem({  className,  inset,  variant = "default",  ...props}: React.ComponentProps<typeof ContextMenuPrimitive.Item> & {  inset?: boolean  variant?: "default" | "destructive"}) {  return (    <ContextMenuPrimitive.Item      data-slot="context-menu-item"      data-inset={inset}      data-variant={variant}      className={cn(        "text-primary focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive [&_svg:not([class*='text-'])]:text-primary relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",        className      )}      {...props}    />  )}function ContextMenuCheckboxItem({  className,  children,  checked,  ...props}: React.ComponentProps<typeof ContextMenuPrimitive.CheckboxItem>) {  return (    <ContextMenuPrimitive.CheckboxItem      data-slot="context-menu-checkbox-item"      className={cn(        "text-primary focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",        className      )}      checked={checked}      {...props}    >      <span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">        <ContextMenuPrimitive.ItemIndicator>          <CheckIcon className="size-4" />        </ContextMenuPrimitive.ItemIndicator>      </span>      {children}    </ContextMenuPrimitive.CheckboxItem>  )}function ContextMenuRadioItem({  className,  children,  ...props}: React.ComponentProps<typeof ContextMenuPrimitive.RadioItem>) {  return (    <ContextMenuPrimitive.RadioItem      data-slot="context-menu-radio-item"      className={cn(        "text-primary focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",        className      )}      {...props}    >      <span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">        <ContextMenuPrimitive.ItemIndicator>          <CircleIcon className="size-2 fill-current" />        </ContextMenuPrimitive.ItemIndicator>      </span>      {children}    </ContextMenuPrimitive.RadioItem>  )}function ContextMenuLabel({  className,  inset,  ...props}: React.ComponentProps<typeof ContextMenuPrimitive.Label> & {  inset?: boolean}) {  return (    <ContextMenuPrimitive.Label      data-slot="context-menu-label"      data-inset={inset}      className={cn(        "text-menu-heading px-2 py-1.5 text-sm font-medium data-[inset]:pl-8",        className      )}      {...props}    />  )}function ContextMenuSeparator({  className,  ...props}: React.ComponentProps<typeof ContextMenuPrimitive.Separator>) {  return (    <ContextMenuPrimitive.Separator      data-slot="context-menu-separator"      className={cn("bg-border -mx-1 my-1 h-px", className)}      {...props}    />  )}function ContextMenuShortcut({  className,  ...props}: React.ComponentProps<"span">) {  return (    <span      data-slot="context-menu-shortcut"      className={cn(        "text-primary ml-auto text-xs tracking-widest",        className      )}      {...props}    />  )}export {  ContextMenu,  ContextMenuTrigger,  ContextMenuContent,  ContextMenuItem,  ContextMenuCheckboxItem,  ContextMenuRadioItem,  ContextMenuLabel,  ContextMenuSeparator,  ContextMenuShortcut,  ContextMenuGroup,  ContextMenuPortal,  ContextMenuSub,  ContextMenuSubContent,  ContextMenuSubTrigger,  ContextMenuRadioGroup,}

Check the import paths to ensure they match your project setup.

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>

Examples

Basic

A simple context menu with a few actions.
Right click here
Use ContextMenuSub, ContextMenuSubTrigger, and ContextMenuSubContent to nest secondary actions.
Right click here

Shortcuts

Add ContextMenuShortcut to show keyboard hints.
Right click here

Groups

Group related actions with ContextMenuGroup and separate them with ContextMenuSeparator.
Right click here

Icons

Combine icons with labels for quick scanning.
Right click here

Checkboxes

Use ContextMenuCheckboxItem for toggles. Control checked state with checked and onCheckedChange.
Right click here

Radio

Use ContextMenuRadioGroup and ContextMenuRadioItem for exclusive choices.
Right click here

Destructive

Use variant="destructive" on ContextMenuItem for destructive actions.
Right click here

RTL

Right-to-left layout with translated labels. Wrap the trigger area in a container with dir="rtl".
انقر بزر الماوس الأيمن هنا

API Reference

The Context Menu composes Radix primitives: ContextMenu, ContextMenuTrigger, ContextMenuContent, ContextMenuItem, ContextMenuCheckboxItem, ContextMenuRadioItem, ContextMenuRadioGroup, ContextMenuLabel, ContextMenuSeparator, ContextMenuShortcut, ContextMenuGroup, ContextMenuSub, ContextMenuSubTrigger, and ContextMenuSubContent. See the Radix Context Menu documentation for behavior and accessibility details.

On this page