Özer

Context Menu

Component 23

About

A right-click context menu with keyboard navigation, typeahead, long-press support on touch, and smart edge-aware positioning that renders through a portal.

Built with React and Tailwind. Copy the prompt and paste it into Claude Code, Cursor or Lovable: your agent adds Context Menu to your project and fits it to your theme.

Code

How Context Menu is used: the demo's code. The component's own source comes with a free account.

Usage.tsx

"use client";

import {
  ContextMenu,
  type ContextMenuItem,
} from "@/components/ui/context-menu";
import { useState } from "react";

const initial = [
  { id: "a", name: "cover-final-v4.png", meta: "PNG · 1.2 MB" },
  { id: "b", name: "hero-crop@2x.png", meta: "PNG · 840 KB" },
  { id: "c", name: "desk-shot-0912.jpg", meta: "JPG · 2.4 MB" },
];

export function ContextMenuDemo() {
  const [files, setFiles] = useState(initial);

  const actions = (id: string): ContextMenuItem[] => [
    { id: "open", label: "Open", shortcut: "↵" },
    { id: "rename", label: "Rename", shortcut: "F2" },
    { id: "copy", label: "Copy link", shortcut: "⌘L" },
    { id: "sep", type: "separator" },
    {
      id: "trash",
      label: "Move to trash",
      shortcut: "⌫",
      onSelect: () => setFiles((prev) => prev.filter((file) => file.id !== id)),
    },
  ];

  return (
    <div className="mx-auto w-full max-w-[380px]">
      {files.length > 0 ? (
        <ul className="space-y-1">
          {files.map((file) => (
            <li key={file.id}>
              <ContextMenu
                label={`Actions for ${file.name}`}
                items={actions(file.id)}
                className="flex h-[50px] items-center rounded-[9px] bg-sub px-3"
              >
                <span className="min-w-0 flex-1">
                  <span className="block truncate text-[12.5px] font-medium text-ink">
                    {file.name}
                  </span>
                  <span className="mt-[1px] block text-[11px] text-ink-3">
                    {file.meta}
                  </span>
                </span>
              </ContextMenu>
            </li>
          ))}
        </ul>
      ) : (
        <div className="grid h-[158px] place-items-center">
          <button
            type="button"
            onClick={() => setFiles(initial)}
            className="mat-cap press h-9 rounded-[9px] px-3.5 text-[13px] font-medium text-ink"
          >
            Put them back
          </button>
        </div>
      )}
    </div>
  );
}

export default ContextMenuDemo;

Dependencies

More by Özer

View all
  • Password Strength

    Password Strength

    1.3K
  • OTP Input

    OTP Input

    803
  • Loading Button

    Loading Button

    602
  • Progress Bar

    Progress Bar

    588
  • Reorder List

    Reorder List

    310
  • Task Steps

    Task Steps

    276
  • Hold to Confirm

    Hold to Confirm

    250
  • Reading Progress

    Reading Progress

    169

Explore more

Part of interior.dev — browse the full library on 21st.dev.