Radial Orbit Menu
A center button that expands into a radial menu arranged in orbit, popping out one item at a time.
This is a WebberUI Pro component
Free during the launch campaign: sign up or sign in, then hit “Copy install command” in the preview above and it installs straight away — no payment, no credit card. The command below returns 401 while you are signed out.
Click the central FAB and the child items spring out one by one along an arc with their angles spread evenly; click again and they retract in reverse. Child items show an outward-facing label on mouse hover or keyboard focus, and radius, arc, and startAngle let you customize the orbit radius and the arc of expansion — a good fit for mobile quick actions or dashboard tool entry points.
npx shadcn@latest add "https://webberui.com/r/radial-orbit-menu.json?t=<install token>"Playground
Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.
<RadialOrbitMenu />
Installation
npx shadcn@latest add "https://webberui.com/r/radial-orbit-menu.json?t=<install token>"Or, once registries are configured in components.json, install it as @webberui/radial-orbit-menu.
Usage
import { RadialOrbitMenu } from "@/components/ui/radial-orbit-menu";
import { Calendar, Mail, Search } from "lucide-react";
<RadialOrbitMenu
radius={96}
items={[
{ icon: <Mail />, label: "Compose email", onClick: () => console.log("mail") },
{ icon: <Calendar />, label: "New event" },
{ icon: <Search />, label: "Search" },
]}
/>To expand across the upper arc only, set arc and startAngle:
<RadialOrbitMenu items={items} radius={110} arc={180} startAngle={0} />Props
| Prop | Type | Default | Description |
|---|---|---|---|
items | RadialOrbitMenuItem[] | — | The child item list; each has icon, label, and onClick? (click callback) |
radius | number | 96 | Distance from a child item's center to the main button's center (px) |
arc | number | 360 | The arc range of expansion (degrees); 360 is a full circle, and below 360 the first and last items sit at the two endpoints |
startAngle | number | 90 | Starting angle of the first child item (degrees); 0 is straight right and 90 is straight up, increasing counterclockwise |
stagger | number | 0.05 | Interval between child items popping out (seconds) |
defaultOpen | boolean | false | Whether it starts expanded (uncontrolled) |
onOpenChange | (open: boolean) => void | — | Callback fired when the expanded state changes |
closeOnSelect | boolean | true | Whether clicking a child item collapses the menu automatically |
triggerLabel | string | "Open quick menu" | Accessible label for the main button |
className | string | — | Forwarded to the outermost container |
Accessibility
- The main button carries
aria-expandedand anaria-label, so the expanded state is visible to assistive technology - Every child item is a native
buttonwith anaria-label, and the label also shows when focused with keyboard Tab - Pressing
Escapecollapses the menu and focus returns to the trigger; clicking outside the menu also collapses it - When the user has "reduce motion" enabled at the system level, the child items simply fade in and out in place with no bouncing displacement or rotation