caliper uidocs

Bloom menu

Free

A button that blooms into a small arc of icon actions.

Installs components/ui/bloom-menu.tsxDepends on @radix-ui/react-slot, lucide-reactMotion none in component source
pnpm dlx shadcn@latest add https://caliperui.site/r/bloom-menu.json

Open the menu.

When to use #

Use it for

  • A quick-add or reaction menu on touch screens.
  • Three to six icon-only actions with clear icons.

Skip it when

  • Actions need text labels; use a dropdown menu.

Installation #

terminal
pnpm dlx shadcn@latest add https://caliperui.site/r/bloom-menu.json

Adds its 3 files to components/ui/, each with its own stylesheet, and installs their packages. No account needed. The first part also adds Caliper UI’s tokens; import them once as in Installation.

Usage #

This is the code behind the preview above.

example.tsx
import { Check, Pencil, Plus } from "lucide-react"
import { useState } from "react"
import { BloomMenu } from "@/components/ui/bloom-menu"

export function QuickAdd() {
  const [last, setLast] = useState("Open the menu.");
  return (
    <div className="grid justify-items-center gap-3 pt-16">
      <BloomMenu
        label="Quick add"
        onSelect={(item) => setLast(`${item.label} added.`)}
        items={[
          { id: "note", label: "Note", icon: <Pencil aria-hidden="true" /> },
          { id: "task", label: "Task", icon: <Check aria-hidden="true" /> },
          { id: "file", label: "File", icon: <Plus aria-hidden="true" /> },
        ]}
      />
      <p role="status" className="text-sm text-muted-foreground">{last}</p>
    </div>
  );
}

API reference #

BloomMenu

component
PropTypeDefault
labelstring"Open menu"
items *readonly BloomItem[]—
onSelect((item: BloomItem) => void)—
classNamestring—

Accessibility #

It exposes menu and menuitem semantics, with aria-expanded and aria-haspopup kept in step with state.

KeyBehaviour
EscapeCloses or cancels, then returns focus to where it came from.

Motion #

It declares no animation in its component source. Any transition comes from its stylesheet, which uses the duration tokens that collapse to instant under prefers-reduced-motion.