Bubble Menu
A menu of floating round bubbles that pop out one by one along a fan, with spring timing plus link and callback support.
Click the main button and the menu items turn into round bubbles that pop out one by one along a fan; click again and they retract from the outside in. Direction, fan angle, radius, and colors are all adjustable.
Loading preview…
npx shadcn@latest add https://webberui.com/r/bubble-menu.jsonPlayground
Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.
180
96
0.05
<BubbleMenu />
Installation
npx shadcn@latest add https://webberui.com/r/bubble-menu.jsonOr, once registries are configured in components.json, install it as @webberui/bubble-menu.
Usage
import { BubbleMenu } from "@/components/ui/bubble-menu";
import { Home, Search, Settings } from "lucide-react";
<BubbleMenu
direction="up"
items={[
{ label: "Home", icon: Home, href: "/" },
{ label: "Search", icon: Search, onClick: () => console.log("search") },
{ label: "Settings", icon: Settings, color: "hsl(280 65% 60%)" },
]}
/>;Every item needs at least a label and an icon. Giving it an href renders a link, or use onClick to bind behavior instead; pick one of the two.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
items | BubbleMenuItem[] | — | Menu items, popping out of the main button one by one |
direction | "up" | "down" | "left" | "right" | "up" | Direction the bubbles expand in |
spread | number | 180 | Total fan angle (degrees) |
radius | number | 96 | Distance from the bubbles to the center of the main button (px) |
size | number | 56 | Main button diameter (px) |
itemSize | number | 46 | Child bubble diameter (px) |
stagger | number | 0.05 | Interval between bubbles popping out (seconds) |
color | string | "hsl(221 83% 53%)" | Primary color (used unless overridden by an item's color) |
showLabels | boolean | true | Show a text label when hovering a bubble while expanded |
icon | LucideIcon | Plus | Main button icon (in the closed state) |
BubbleMenuItem
| Field | Type | Description |
|---|---|---|
label | string | Bubble label, also used as the aria-label |
icon | LucideIcon | A lucide-react icon component |
href | string? | Navigation link; renders as an a when set |
onClick | () => void | Click callback; use this or href |
color | string? | Override the color of this bubble alone |
Accessibility
- The main button carries
aria-expandedand anaria-label, toggling the open state - Every bubble carries an
aria-label; while collapsed, the bubble layer is markedaria-hidden - When the user has "reduce motion" enabled at the system level, a very short fade in and out replaces the spring displacement