Bone
Out-of-the-box tokens. Warm slices on near-black canvas. Lime on hover.
A pie-menu for the modern web.
Right-click anywhere on this page —
a six-wedge dock will rise to meet your cursor.
Out-of-the-box tokens. Warm slices on near-black canvas. Lime on hover.
Translucent slices, backdrop blur, subtle ring. For overlays on busy canvases.
Pure-black slices with electric-lime glow. Game UIs, creative tools, bold brands.
Off-white substrate with ink slices. Editorial tools, document apps, light mode.
Five built-in animations — spring, fade, pop, stagger, iris — orchestrated through a single GSAP timeline. Bring your own keyframes via the custom hook.
Twelve CSS variables expose every surface, plus per-element classNames slots. Render anything in any wedge with the render escape hatch.
Open by context-menu, by keyboard combo, or imperatively through a ref handle. Mix and match. Position controlled or uncontrolled — the dock follows.
Boundary-aware: defers document reads to useEffect, hydrates without flash, and ships with a 'use client' directive baked into the entry bundles.
Full keyboard navigation, menu + menuitem roles, aria-activedescendant, and an automatic prefers-reduced-motion bypass.
Lazy-loads GSAP only on first open. Presets live in a separate entry. ESM + CJS dual exports, full TypeScript types, zero runtime config.
import { RadialDock } from 'react-radial-dock';
import 'react-radial-dock/styles.css';
export default function Page() {
return (
<RadialDock
items={[
{ id: 'star', label: 'Star', icon: <Star />, onSelect: () => star() },
{ id: 'edit', label: 'Edit', icon: <Pencil />, onSelect: () => edit() },
{ id: 'mark', label: 'Bookmark', icon: <Bookmark />, onSelect: () => mark() },
{ id: 'pin', label: 'Pin', icon: <Pin />, onSelect: () => pin() },
]}
triggers={{ rightClick: true, hotkey: 'mod+e' }}
animation="spring"
/>
);
}<RadialDock/> at the root of your app.ref.current.open(x, y).--rrd-* CSS variables, or pass a theme prop.Each item.render receives { hovered, index } — return any JSX.
<RadialDock
items={[
{ id: '1', label: 'Star', icon: <span>⭐</span>, onSelect: () => {} },
{ id: '2', label: 'Edit', icon: <span>✏️</span>, onSelect: () => {} },
{ id: '3', label: 'Bookmark', icon: <span>🔖</span>, onSelect: () => {} },
{ id: '4', label: 'Pin', icon: <span>📍</span>, onSelect: () => {} },
]}
outerRadius={110}
innerRadius={55}
sliceGap={2}
iconSize={32}
startAngle={0}
direction="clockwise"
animation="spring"
reducedMotion="auto"
theme={{
bg: 'rgba(20, 20, 20, 0.78)',
sliceFill: 'rgba(236, 230, 216, 0.06)',
sliceFillHover: '#d4ff00',
iconColor: '#ece6d8',
labelColor: 'rgba(255,255,255,0.85)',
}}
/>| Prop | Type | Description |
|---|---|---|
| items REQ | Array<{ id, label, icon, onSelect, disabled? }> | The wedges. Minimum 3 required to render. Each item exposes its own onSelect callback. |
| triggers | { rightClick?: boolean; hotkey?: string | false } | How the dock opens. Defaults to right-click only. Hotkey accepts mod+key combos. |
| animation | 'spring' | 'fade' | 'pop' | 'stagger' | 'iris' | (ctx) => gsap.Timeline | Built-in preset name or a custom timeline factory. Receives the animation context. |
| theme | Partial<RadialDockTheme> | Override colors, blur, shadow, ring stroke. Twelve tokens total. Composes with CSS vars. |
| outerRadius / innerRadius / iconRadius | number | 'auto' | Geometry. Auto picks midpoint for icon ring. Inner must be ≤ outer − 20. |
| startAngle / direction | number (deg) / 'clockwise' | 'counter-clockwise' | Slice 0 placement and rotation order. Defaults to 0° (top), clockwise. |
| open / onOpenChange / position | boolean / (next) => void / { x, y } | Optional controlled mode. Provide all three to manage state externally. |
| reducedMotion | 'auto' | 'always' | 'never' | Motion strategy. Auto reads prefers-reduced-motion. Always disables transitions entirely. |
A pie chart that bites back.