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.
Bring this into your project
Run this command in your project folder. The CLI adds the source and dependencies; then follow the usage example below.
npx webberui@latest add bubble-menu.enPlayground
Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.
<BubbleMenu/>
The complete example includes the preview layout and data. Install the component first, then paste this file into your project.
Installation
npx webberui@latest add https://webberui.com/r/bubble-menu.en.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