Context Menu Bubble
tripled/context-menu-bubble-shadcnuiFreeComponent
Right-click reveals circular expanding radial menu with icons
Live preview
live · rendered by the registry
Rendered by tripled on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://ui.tripled.work/r/context-menu-bubble-shadcnui.jsonSource
1"use client";23import { AnimatePresence, motion } from "framer-motion";4import { Copy, Edit, MoreVertical, Share2, Trash2 } from "lucide-react";5import { MouseEvent, useRef, useState } from "react";67type MenuItem = {8 label: string;9 icon: React.ReactNode;10 onClick: () => void;11 danger?: boolean;12};1314type ContextMenuBubbleProps = {15 items?: MenuItem[];16};1718export function ContextMenuBubble({19 items = [20 { label: "Edit", icon: <Edit className="h-4 w-4" />, onClick: () => {} },21 { label: "Copy", icon: <Copy className="h-4 w-4" />, onClick: () => {} },22 { label: "Share", icon: <Share2 className="h-4 w-4" />, onClick: () => {} },23 {24 label: "Delete",25 icon: <Trash2 className="h-4 w-4" />,26 onClick: () => {},27 danger: true,28 },29 ],30}: ContextMenuBubbleProps) {31 const [isOpen, setIsOpen] = useState(false);32 const [position, setPosition] = useState({ x: 0, y: 0 });33 const triggerRef = useRef<HTMLButtonElement>(null);34 const containerRef = useRef<HTMLDivElement>(null);3536 const updatePosition = () => {37 if (triggerRef.current && containerRef.current) {38 const buttonRect = triggerRef.current.getBoundingClientRect();39 const containerRect = containerRef.current.getBoundingClientRect();40 setPosition({41 x: buttonRect.left + buttonRect.width / 2 - containerRect.left,42 y: buttonRect.top + buttonRect.height / 2 - containerRect.top,43 });44 }45 };4647 const handleContextMenu = (e: MouseEvent) => {48 e.preventDefault();49 updatePosition();50 setIsOpen(true);51 };5253 const handleClick = () => {54 updatePosition();55 setIsOpen(!isOpen);56 };5758 const closeMenu = () => setIsOpen(false);5960 const itemCount = items.length;61 const radius = 80;62 const angleStep = (2 * Math.PI) / itemCount;6364 return (65 <div66 ref={containerRef}67 className="relative flex h-64 w-full items-center justify-center overflow-hidden rounded-2xl"68 >69 <motion.button70 ref={triggerRef}71 onContextMenu={handleContextMenu}72 onClick={handleClick}73 whileHover={{ scale: 1.1 }}74 whileTap={{ scale: 0.9 }}75 className="flex h-12 w-12 items-center justify-center rounded-full bg-primary text-primary-foreground"76 >77 <MoreVertical className="h-5 w-5" />78 </motion.button>7980 <AnimatePresence>81 {isOpen && (82 <>83 <motion.div84 initial={{ opacity: 0 }}85 animate={{ opacity: 1 }}86// … truncated
What it pulls in
npm packages
Other registry items
Files it writes
More from tripled
All 282 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| AI Chat Interfaceai-chat-interface-shadcnui | tripled | Components | Free | 2 deps | |
| AI Glow Inputai-glow-input-shadcnui | tripled | Components | Free | 2 deps | |
| AI Loading Skeletonai-loading-skeleton-shadcnui | tripled | Components | Free | 2 deps | |
| AI Response Typing Streamai-response-typing-shadcnui | tripled | Components | Free | 2 deps | |
| AI Unlock Animationai-unlock-animation-shadcnui | tripled | Components | Free | 2 deps | |
| Animated Accordionanimated-accordion-shadcnui | tripled | Components | Free | 2 deps | |
| Animated Card Stackanimated-card-stack-baseui | tripled | Components | Free | 2 deps | |
| Animated Card Stackanimated-card-stack-shadcnui | tripled | Components | Free | 2 deps |
