Menu wheel
100xui/menu-wheelFreeBlock
An interactive, animated radial menu that smoothly expands to reveal options in a circular layout. Powered by Motion, it features a fluid 'press, hover, and release' interaction model, making it perfect for housing grouped actions or quick-access settings in a compact, modern UI.
Live preview
live · rendered by the registry
Rendered by 100xui on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://100xui.com/r/menu-wheel.jsonSource
1"use client";23import {4 AnimatePresence,5 motion,6 MotionConfig,7 type MotionProps,8 type Transition,9 useAnimate,10} from "motion/react";11import React, {12 type ComponentProps,13 createContext,14 useContext,15 useEffect,16 useRef,17 useState,18} from "react";19import { XIcon } from "lucide-react";2021import { cn } from "@/lib/utils";2223const TRANSITION: Transition = {24 ease: "easeOut",25 duration: 0.25,26};2728type MenuWheelContextType = {29 open: boolean;30 setOpen: React.Dispatch<React.SetStateAction<boolean>>;31 activeValue: string | null;32 setActiveValue: React.Dispatch<React.SetStateAction<string | null>>;33 showCurrent: boolean;34 onValueChange?: (value: string) => void;35};3637const MenuWheelContext = createContext<MenuWheelContextType | null>(null);3839export function useMenuWheelContext() {40 const ctx = useContext(MenuWheelContext);41 if (!ctx) {42 throw new Error("MenuWheel components must be used within a <MenuWheel/>");43 }44 return ctx;45}4647type MenuWheelContainerContextType = {48 totalItems: number;49 moveHighlight: (index: number) => void;50 clearHighlight: () => void;51};5253const MenuWheelContainerContext =54 createContext<MenuWheelContainerContextType | null>(null);5556export function useMenuWheelContainerContext() {57 const ctx = useContext(MenuWheelContainerContext);58 if (!ctx) {59 throw new Error(60 "MenuWheelItem components must be used within a <MenuWheelContainer/>"61 );62 }63 return ctx;64}6566interface MenuWheelProps extends ComponentProps<"div"> {67 showCurrent?: boolean; // Whether to highlight the currently selected item68 defaultValue?: string; // The default value to be selected when the component mounts69 onValueChange?: (value: string) => void; // Callback function to handle value changes70}7172export function MenuWheel({73 children,74 className,75 showCurrent = true,76 defaultValue,77 onValueChange,78 ...props79}: MenuWheelProps) {80 const [open, setOpen] = useState(false);81 const [activeValue, setActiveValue] = useState<string | null>(82 defaultValue ?? null83 );8485 useEffect(() => {86 const handleMouseUp = () => {87 setOpen(false);88 };89 if (open) {90 window.addEventListener("mouseup", handleMouseUp);91 }92 return () => window.removeEventListener("mouseup", handleMouseUp);93 }, [open]);9495 return (96 <MenuWheelContext.Provider97 value={{98 open,99 setOpen,100 activeValue,101// … truncated
What it pulls in
npm packages
Files it writes
More from 100xui
All 14 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Apple galleryapple-gallery | 100xui | Blocks | Free | 1 dep | |
| Chat bento cardchat-bento-card | 100xui | Blocks | Free | 1 dep | |
| demosdemos | 100xui | Blocks | Free | no deps · 12 files | |
| In-page navbarin-page-navbar | 100xui | Blocks | Free | 1 dep · 2 files | |
| internalsinternals | 100xui | Blocks | Free | no deps · 4 files | |
| iPhone 3D mockupiphone-3d-mockup | 100xui | Blocks | Free | no deps | |
| Morph modalmorph-modal | 100xui | Blocks | Free | 1 dep | |
| Motion Dockmotion-dock | 100xui | Blocks | Free | 1 dep · 3 files |
