zeroUI

Radial menu

A radial menu for React, the game weapon wheel: choices around a ring, picked by the pointer's direction or the arrow keys.

Install

terminal
# once per project: where @zeroui items come frompnpm dlx shadcn@latest registry add @zeroui=https://zeroui.catforest.dev/r/{name}.jsonpnpm dlx shadcn@latest add @zeroui/radial-menu

Examples

A quick-use wheel

Point anywhere, then click; or use the arrows and Enter.

radial-menu-quick.tsx
import { useState } from "react";import { CellIcon } from "@/components/zero/icons/cell";import { ChipIcon } from "@/components/zero/icons/chip";import { CrateIcon } from "@/components/zero/icons/crate";import { FlareIcon } from "@/components/zero/icons/flare";import { KeyIcon } from "@/components/zero/icons/key";import { KitIcon } from "@/components/zero/icons/kit";import { RadialMenu, RadialMenuItem } from "@/components/zero/radial-menu";const wheel = [  { value: "kit", label: "Repair kit", icon: KitIcon },  { value: "cell", label: "Power cell", icon: CellIcon },  { value: "flare", label: "Signal flare", icon: FlareIcon },  { value: "chip", label: "Route chip", icon: ChipIcon },  { value: "key", label: "Gate key", icon: KeyIcon },  { value: "crate", label: "Drop the crate", icon: CrateIcon, disabled: true },];export default function RadialMenuQuick() {  const [used, setUsed] = useState<string | null>(null);  return (    <div className="grid justify-items-center gap-4">      <RadialMenu aria-label="Quick use" onSelect={setUsed}>        {wheel.map((item) => (          <RadialMenuItem            key={item.value}            value={item.value}            label={item.label}            disabled={item.disabled}          >            <item.icon />          </RadialMenuItem>        ))}      </RadialMenu>      <p className="font-medium font-zero-text text-zero-sm text-zero-text-2">        {used          ? `Used: ${wheel.find((item) => item.value === used)?.label}`          : "Point anywhere, then click; or use the arrows and Enter."}      </p>    </div>  );}

Behaviour

Up to eight items around a ring, the first at the top, going clockwise. Pointing anywhere picks the item in that direction, so a flick of the mouse is enough; a bright wedge swings to it and the centre names it. A click or Enter chooses it.

The arrow keys go round the ring. Focus stays on the wheel and the picked item is its active descendant, so screen readers hear each as it is reached. It is the wheel only: show it where and when you need it, on a held key or in an overlay.

Props

RadialMenu

PropTypeDefaultDescription
onSelect(value: string) => void—When an item is chosen.
defaultValuestring—The item picked when it opens.

RadialMenuItem

PropTypeDefaultDescription
valuestring—What onSelect gets.
labelstring—Its name: said by screen readers and shown in the centre.
disabledboolean—Shown dim; cannot be chosen.