Skip to main content

Overview

The ContextMenu component provides a right-click menu with customizable options and actions.

Basic Usage

  • Code
  • Preview
import { useState } from "react";
import ContextMenu from "@/ui/context-menu";
import { Copy } from "@/assets/icons/copy.tsx";
import { HouseAdd } from "@/assets/icons/house-add.tsx";
import { TrashEmpty } from "@/assets/icons/trash-empty.tsx";

export default function ContextMenuBasicExample() {
    const [lastAction, setLastAction] = useState<string>("None");
    return (
        <div className="flex items-center flex-col gap-4 w-full">
            <ContextMenu.Root>
                <ContextMenu.Trigger trigger="right">
                    <div className="font-mono w-full max-w-md rounded-lg border-2 border-dashed border-neutral-80 bg-neutral-98 p-6 text-center text-sm text-neutral-40">
                    Right-click anywhere in this area
                    </div>
                </ContextMenu.Trigger>

                <ContextMenu.Content>
                    <ContextMenu.List>
                        <ContextMenu.Item icon={<Copy />} onSelect={() => setLastAction("copy")}>
                            Copy
                        </ContextMenu.Item>
                        <ContextMenu.Item icon={<HouseAdd />} onSelect={() => setLastAction("paste")}>
                            Paste
                        </ContextMenu.Item>
                        <ContextMenu.Item
                            icon={<TrashEmpty />}
                            onSelect={() => setLastAction("delete")}
                        >
                            Delete
                        </ContextMenu.Item>
                    </ContextMenu.List>
                </ContextMenu.Content>
            </ContextMenu.Root>

            <div className="text-sm text-neutral-60 font-mono">
                Last action: <span className="font-medium text-neutral-0">{lastAction}</span>
            </div>
        </div>
    );
}


ComponentPropTypeDefaultDescription
RootchildrenReact.ReactNodeWraps trigger and menu content
RootclassNamestringAdditional classes for wrapper
TriggerchildrenReact.ReactNodeElement that opens the menu
Triggertrigger'left' | 'right' | 'both''left'Choose which mouse button opens the menu
TriggerclassNamestringAdditional classes
ContentchildrenReact.ReactNodeMenu body
Contentwidthnumber260Menu width in pixels
Contentplacement'auto' | 'bottom-start' | 'bottom-end' | 'top-start' | 'top-end''auto'Preferred menu placement
Contentoffsetnumber6Distance between trigger and menu
ContentclassNamestringAdditional classes
ListchildrenReact.ReactNodeMenu list container
ListclassNamestringAdditional classes
LabelchildrenReact.ReactNodeSection heading text
ItemchildrenReact.ReactNodeItem label
ItemiconReact.ReactNodeOptional leading icon
ItemshortcutstringKeyboard shortcut helper text
ItemonSelect() => voidSelection handler
ItemdisabledbooleanfalseDisable item interaction
ItemclassNamestringAdditional classes
GroupvaluestringSelected value (radio behaviour)
GrouponValueChange(value: string) => voidSelection change handler

Examples

File Context Menu

  • Code
  • Preview
import { useState } from "react";
import ContextMenu from "@/ui/context-menu";
import { Eye } from "@/assets/icons/eye.tsx";
import { EditPencil } from "@/assets/icons/edit-pencil.tsx";
import { Email } from "@/assets/icons/email.tsx";
import { Copy } from "@/assets/icons/copy.tsx";
import { TrashEmpty } from "@/assets/icons/trash-empty.tsx";

const FILE = {
    id: 1,
    name: "Quarterly_Report.pdf",
    size: "2.4 MB",
};

export default function ContextMenuFileExample() {
    const [lastAction, setLastAction] = useState("No action yet");

    const handleAction = (action: string) => {
        setLastAction(`${action}${FILE.name}`);
    };

    return (
        <div className="flex items-center flex-col gap-4 w-full">
            <ContextMenu.Root>
                <ContextMenu.Trigger trigger="right">
                    <div className="w-full max-w-md cursor-pointer rounded-lg border border-neutral-200 bg-white p-4 text-sm shadow-sm hover:bg-neutral-98">
                        <div className="font-medium text-neutral-0">{FILE.name}</div>
                        <div className="text-neutral-40">{FILE.size}</div>
                        <div className="mt-2 text-xs text-neutral-50 font-mono">Right-click to manage file</div>
                    </div>
                </ContextMenu.Trigger>

                <ContextMenu.Content>
                    <ContextMenu.List>
                        <ContextMenu.Item icon={<Eye />} onSelect={() => handleAction("View file")}>
                            View
                        </ContextMenu.Item>
                        <ContextMenu.Item icon={<EditPencil />} onSelect={() => handleAction("Edit file")}>
                            Edit
                        </ContextMenu.Item>
                        <ContextMenu.Item icon={<Email />} onSelect={() => handleAction("Share via email")}>Email</ContextMenu.Item>
                        <ContextMenu.Item icon={<Copy />} onSelect={() => handleAction("Share link")}>Copy Link</ContextMenu.Item>
                        <ContextMenu.Item icon={<TrashEmpty />} className="[&>svg]:text-error-50 text-error-50" onSelect={() => handleAction("Delete file")}>
                            Delete
                        </ContextMenu.Item>
                    </ContextMenu.List>
                </ContextMenu.Content>
            </ContextMenu.Root>

            <div className="text-sm text-neutral-60 font-mono">
                {lastAction}
            </div>
        </div>
    );
}
I