Skip to content
WANCRAFT

D.45Navigation & Menus

Radial Menu

A circular menu that fans actions around a trigger or the pointer, with direction-aware highlighting.

NewReactMotionTailwindadvanced

Overview

Radial Menu spreads its items around a central trigger on a staggered spring, either across a full circle or a partial arc set by startAngle and arc. While it is open, the direction of the pointer from the centre highlights the item it points at, so a flick towards an action is enough to target it. It can also open at the pointer on right-click inside any target area. Under the hood it is a WAI-ARIA menu button: role="menu" with menuitems, roving focus that rotates with the arrow keys, Home / End, Escape to close with focus returned, and labels that appear as tooltips beside the active item.

01Installation

Method 01 · Registry

CLI verified

Uses the shadcn CLI in a project initialised with shadcn init. Installs the file to components/ui/radial-menu.tsx and adds its dependencies.

npx shadcn@latest add https://wancraft.my/r/radial-menu.json

Method 02 · Copy and paste

  1. 1. Install the dependencies below.
  2. 2. Copy the source from the Code tab into components/ui/radial-menu.tsx.
  3. 3. Import it and adjust props.
npm install motion
Dependencies
motion
Peer
react ≥ 18, tailwindcss ≥ 4
Added
13 Oct 2026
Updated
—

02Usage

The default configuration. Change properties above to generate a tailored example in the Usage tab.

example.tsx
import { RadialMenu, type RadialMenuItem } from "@/components/ui/radial-menu";

export function RadialMenuExample() {
  const items: RadialMenuItem[] = [
    { id: "copy", label: "Copy", icon: <span>C</span>, onSelect: () => console.log("copy") },
    { id: "share", label: "Share", icon: <span>S</span> },
    { id: "pin", label: "Pin", icon: <span>P</span> },
    { id: "delete", label: "Delete", icon: <span>D</span> },
  ];

  return (
    <RadialMenu items={items} label="Quick actions" />
  );
}

03Props

PropTypeDefaultDescription
itemsRadialMenuItem[]—{ id: string; label: string; icon: ReactNode; onSelect?: () => void; disabled?: boolean }.
trigger"button" | "contextmenu""button"Open from a central trigger, or at the pointer on right-click inside children.
radiusnumber96Distance from the centre to each item, in px.
startAnglenumber-90Angle of the first item in degrees (0 = right, -90 = up); items continue clockwise.
arcnumber360Sweep of the fan in degrees. 360 spreads items around a full circle.
itemSizenumber44Diameter of each item in px.
labels"active" | "always" | "none""active"Which visible labels to show. Items are always labelled for assistive tech.
staggernumber35Delay between items as they fan out, in ms.
spring{ stiffness: number; damping: number; mass: number }{ stiffness: 420, damping: 26, mass: 0.8 }Spring used to fan items out.
accentstring"#FF7448"Trigger, active item and focus ring colour.
labelstring"Actions"Accessible name of the trigger (or target area) and the menu.
defaultOpenbooleanfalseStart open. Focus is not moved on mount.
onSelect(item: RadialMenuItem) => void—Called after any item is chosen.
onOpenChange(open: boolean) => void—Called when the menu opens or closes.
childrenReactNode—Target area content for trigger="contextmenu".
...propsHTMLAttributes<HTMLDivElement>—Native attributes are forwarded to the root.

04Features

  • 01Full-circle or partial-arc layouts from startAngle and arc
  • 02Staggered spring fan-out and a reversed fold-in on close
  • 03Pointer direction highlights the item it points at (mouse and pen)
  • 04Right-click mode opens the ring at the pointer and keeps it inside the target area
  • 05Tooltip labels for the active item or every item
motion · springmotion · staggerinput · clickinput · pointerinput · keyboardinput · focus

05Accessibility

  • Menu button pattern: the trigger has aria-haspopup="menu", aria-expanded and aria-controls; the ring is role="menu" with role="menuitem" buttons.
  • Opening from the keyboard moves focus to the first item (Arrow Up opens on the last).
  • Arrow keys rotate focus around the ring and wrap; Home / End jump; disabled items are skipped.
  • Escape closes and returns focus to the trigger; Tab or a press outside closes the menu.
  • In right-click mode the target area is focusable and opens the menu with Shift+F10 or the Menu key, described by a hint.
  • Icons are decorative; each item is named by its label. With prefers-reduced-motion items appear in place without movement.

06Limitations

  • Very small radii or many items can make items overlap; increase radius or reduce the arc.