Context Menu
godui/context-menuFreeComponent
A right-click menu that springs from the cursor point and flips to stay in the viewport, with shortcuts and destructive actions.
Install it
npx shadcn@latest add https://godui.design/r/context-menu.jsonSource
1"use client";23import { AnimatePresence, motion, useReducedMotion } from "framer-motion";4import * as React from "react";56export type ContextMenuItem =7 | { type: "separator" }8 | { type: "label"; label: React.ReactNode }9 | {10 type?: "item";11 label: React.ReactNode;12 icon?: React.ReactNode;13 shortcut?: string;14 disabled?: boolean;15 destructive?: boolean;16 onSelect?: () => void;17 };1819export type ContextMenuProps = React.HTMLAttributes<HTMLDivElement> & {20 items: ContextMenuItem[];21 children: React.ReactNode;22};2324type Coords = { x: number; y: number; flipX: boolean; flipY: boolean };2526const ContextMenu = React.forwardRef<HTMLDivElement, ContextMenuProps>(27 ({ items, children, className, ...props }, ref) => {28 const reduceMotion = useReducedMotion();29 const [coords, setCoords] = React.useState<Coords | null>(null);30 const menuRef = React.useRef<HTMLDivElement>(null);3132 React.useEffect(() => {33 if (!coords) return;34 const onDown = (e: MouseEvent) => {35 if (menuRef.current && !menuRef.current.contains(e.target as Node)) {36 setCoords(null);37 }38 };39 const onScroll = () => setCoords(null);40 const onKey = (e: KeyboardEvent) => {41 if (e.key === "Escape") setCoords(null);42 };43 document.addEventListener("mousedown", onDown);44 window.addEventListener("scroll", onScroll, true);45 document.addEventListener("keydown", onKey);46 return () => {47 document.removeEventListener("mousedown", onDown);48 window.removeEventListener("scroll", onScroll, true);49 document.removeEventListener("keydown", onKey);50 };51 }, [coords]);5253 React.useEffect(() => {54 if (coords) {55 menuRef.current56 ?.querySelector<HTMLElement>("[data-menu-item]")57 ?.focus();58 }59 }, [coords]);6061 const openAt = (clientX: number, clientY: number) => {62 const menuW = 220;63 const menuH = Math.min(items.length * 40 + 12, 360);64 const flipX = clientX + menuW > window.innerWidth;65 const flipY = clientY + menuH > window.innerHeight;66 setCoords({ x: clientX, y: clientY, flipX, flipY });67 };6869 const moveFocus = (dir: 1 | -1) => {70 const nodes = Array.from(71 menuRef.current?.querySelectorAll<HTMLElement>("[data-menu-item]") ??72 [],73 );74 if (!nodes.length) return;75 const idx = nodes.indexOf(document.activeElement as HTMLElement);76// … truncated
What it pulls in
npm packages
Other registry items
Files it writes
More from godui
All 105 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Accordionaccordion | godui | Components | Free | 1 dep | |
| Agent Flowagent-flow | godui | Components | Free | 1 dep | |
| Agent Timelineagent-timeline | godui | Components | Free | 1 dep | |
| Animated Beamanimated-beam | godui | Components | Free | 1 dep | |
| Animated Testimonialsanimated-testimonials | godui | Components | Free | 1 dep | |
| Animated Tooltipanimated-tooltip | godui | Components | Free | 1 dep | |
| App Showcaseapp-showcase | godui | Components | Free | 1 dep | |
| Aurora Textaurora-text | godui | Components | Free | no deps |
