Context Menu
Overlay & FeedbackRight-click context menu with items.
Preview
Right-click here
Usage
example.jsx
import { ContextMenu, ContextMenuItem } from "@/components/ui/context-menu";
export default function Example() {
return <ContextMenu />;
}Source Code
Copy this file into components/ui/context-menu.jsx in your project.
context-menu.jsx
"use client";
import { forwardRef, useState, useRef, useEffect } from "react";
import { cn } from "@/lib/utils";
const ContextMenu = forwardRef(({ className, trigger, children, ...props }, ref) => {
const [open, setOpen] = useState(false);
const [pos, setPos] = useState({ x: 0, y: 0 });
const menuRef = useRef(null);
useEffect(() => {
const handler = () => setOpen(false);
document.addEventListener("click", handler);
return () => document.removeEventListener("click", handler);
}, []);
const onContextMenu = (e) => {
e.preventDefault();
setPos({ x: e.clientX, y: e.clientY });
setOpen(true);
};
return (
<>
<div onContextMenu={onContextMenu}>{trigger}</div>
{open && (
<div ref={(el) => { menuRef.current = el; if (typeof ref === "function") ref(el); else if (ref) ref.current = el; }}
className={cn("fixed z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md", className)}
style={{ top: pos.y, left: pos.x }}
{...props}
>
{children}
</div>
)}
</>
);
});
ContextMenu.displayName = "ContextMenu";
const ContextMenuItem = forwardRef(({ className, ...props }, ref) => (
<button ref={ref} className={cn("relative flex w-full cursor-pointer select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground", className)} {...props} />
));
ContextMenuItem.displayName = "ContextMenuItem";
export { ContextMenu, ContextMenuItem };
Quick Install
Make sure you have the cn() utility set up. It requires clsx and tailwind-merge.
npm install clsx tailwind-merge