WebberUI

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.json

Playground

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.json

Or, 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

PropTypeDefaultDescription
itemsBubbleMenuItem[]Menu items, popping out of the main button one by one
direction"up" | "down" | "left" | "right""up"Direction the bubbles expand in
spreadnumber180Total fan angle (degrees)
radiusnumber96Distance from the bubbles to the center of the main button (px)
sizenumber56Main button diameter (px)
itemSizenumber46Child bubble diameter (px)
staggernumber0.05Interval between bubbles popping out (seconds)
colorstring"hsl(221 83% 53%)"Primary color (used unless overridden by an item's color)
showLabelsbooleantrueShow a text label when hovering a bubble while expanded
iconLucideIconPlusMain button icon (in the closed state)

BubbleMenuItem

FieldTypeDescription
labelstringBubble label, also used as the aria-label
iconLucideIconA lucide-react icon component
hrefstring?Navigation link; renders as an a when set
onClick() => voidClick callback; use this or href
colorstring?Override the color of this bubble alone

Accessibility

  • The main button carries aria-expanded and an aria-label, toggling the open state
  • Every bubble carries an aria-label; while collapsed, the bubble layer is marked aria-hidden
  • When the user has "reduce motion" enabled at the system level, a very short fade in and out replaces the spring displacement

On this page