react-radial-dock
v1.0.0MIT~6 KB GZREACT 18 +
FILE 01 / HEROREACT · COMPONENT · GSAPLIVERIGHT-CLICK READY

RadialDock/tsx

A pie-menu for the modern web.
Right-click anywhere on this page —
a six-wedge dock will rise to meet your cursor.

Try the playground
TIPRight-click anywhere on this page to summon the dock
02 / VARIANTS

Four flavors,
one component— theme tokens, custom render, or both. The dock bends.

SWAP THEMES
WITHOUT FORKING
A / DEFAULT

Bone

Out-of-the-box tokens. Warm slices on near-black canvas. Lime on hover.

B / GLASS

Frosted

Translucent slices, backdrop blur, subtle ring. For overlays on busy canvases.

C / NEON

Acid

Pure-black slices with electric-lime glow. Game UIs, creative tools, bold brands.

D / PAPER

Inverted

Off-white substrate with ink slices. Editorial tools, document apps, light mode.

03 / SPECS

Precision-
engineered— twelve concerns, one tiny component, zero compromises.

SIX HIGHLIGHTS
OF THIRTY-SOMETHING
01GSAP

Timeline-driven motion

Five built-in animations — spring, fade, pop, stagger, iris — orchestrated through a single GSAP timeline. Bring your own keyframes via the custom hook.

5 PRESETS · CUSTOM TIMELINES
02HEADLESS

Themable to the bone

Twelve CSS variables expose every surface, plus per-element classNames slots. Render anything in any wedge with the render escape hatch.

CSS VARS · CLASSES · RENDER PROPS
03TRIGGERS

Right-click, hotkey, ref

Open by context-menu, by keyboard combo, or imperatively through a ref handle. Mix and match. Position controlled or uncontrolled — the dock follows.

3 TRIGGER MODES · CONTROLLED OR NOT
04SSR

Server-render safe

Boundary-aware: defers document reads to useEffect, hydrates without flash, and ships with a 'use client' directive baked into the entry bundles.

NEXT.JS APP ROUTER READY
05A11Y

Keyboard, ARIA, motion

Full keyboard navigation, menu + menuitem roles, aria-activedescendant, and an automatic prefers-reduced-motion bypass.

WCAG-MINDED · REDUCED-MOTION AWARE
06SIZE

Tree-shakable, ~6 KB

Lazy-loads GSAP only on first open. Presets live in a separate entry. ESM + CJS dual exports, full TypeScript types, zero runtime config.

ESM · CJS · TYPED · LAZY
04 / USAGE

Five lines
of JSX— fewer if you trust the defaults. Optional everything else.

DROP-IN
BY DESIGN
app/page.tsxTSX
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"
    />
  );
}
01
Install.
npm i react-radial-dock
(peer: react ≥ 18, gsap ≥ 3.12)
02
Mount once.
Drop a single <RadialDock/> at the root of your app.
03
Trigger.
Right-click. Or press the hotkey. Or ref.current.open(x, y).
04
Theme.
Override --rrd-* CSS variables, or pass a theme prop.
05 / PLAYGROUND

Tweak everything,
watch it react— real component, real props, live preview. Copy the JSX when you're happy.

REAL LIBRARY
NO SHORTCUTS

Items / Wedges

Geometry

Outer Radius110px
Inner Radius55px
Slice Gap2px
Icon Size32px
Start Angle0°
Directionclockwise

Animation

Presetspring
Reduced Motionauto

Theme

Slice fill (hover)
Icon color
Slice fill
Background
Label color

Custom Render

Each item.render receives { hovered, index } — return any JSX.

STAGE / ALWAYS-OPEN— hover any wedge —
GENERATED · YOUR CONFIG · TSX
<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)',
  }}
/>
06 / SURFACE

Eight props,
one ref handle— the public API. Everything else has a sensible default.

FULLY TYPED
D.TS GENERATED
PropTypeDescription
items REQArray<{ 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.TimelineBuilt-in preset name or a custom timeline factory. Receives the animation context.
themePartial<RadialDockTheme>Override colors, blur, shadow, ring stroke. Twelve tokens total. Composes with CSS vars.
outerRadius / innerRadius / iconRadiusnumber | 'auto'Geometry. Auto picks midpoint for icon ring. Inner must be ≤ outer − 20.
startAngle / directionnumber (deg) / 'clockwise' | 'counter-clockwise'Slice 0 placement and rotation order. Defaults to 0° (top), clockwise.
open / onOpenChange / positionboolean / (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.

NO CONFIG·FIVE PRESETS·SIX KILOBYTES·MIT LICENSE