Mitosis Menu
NewCustomize
Up
Distance88px
Spread150°
Size56px
Option size46px
Goo1.00
Stagger35ms
Bounce0.30
Installation
npx shadcn@latest add https://uibrik.com/r/mitosis-menu.jsonInstall the packages
npm install @tabler/icons-react motionAdd the cn helper
Imports
cnfrom@/lib/utils, whichshadcn initcreates. Add it by hand without shadcn.Copy the source into your project
components/uibrik/mitosis-menu/mitosis-menu.tsx"use client"; import { useEffect, useId, useMemo, useRef, useState, type KeyboardEvent, type ReactNode } from "react"; import { animate, motion, motionValue, type MotionValue } from "motion/react"; import { IconCameraFilled, IconFileFilled, IconMicrophoneFilled, IconPhotoFilled, IconPlus } from "@tabler/icons-react"; import { cn } from "@/lib/utils"; // Mitosis menu. A round button that divides into its options like a cell. // Each option buds off the parent as a small droplet, a neck of liquid // stretches between them, thins and snaps, and the droplet swells into a // bubble; closing pulls them back in and they fuse. Each bubble is a circle // tied to the parent by a stroke that thins as it travels, all drawn through // an SVG goo filter (blur, then a hard alpha threshold) so shapes that are // close melt into one and a neck too thin to survive the threshold breaks. // Icons sit in a layer above the filter so they stay crisp. export type MitosisItem = { id: string; label: string; icon?: ReactNode }; export type MitosisMenuProps = { items?: MitosisItem[]; /** Which way the options fan out. */ direction?: "up" | "down" | "left" | "right" | "radial"; /** Distance from the button's centre to each option's, px. */ distance?: number;
Adds the files to
components/uibrik/mitosis-menu and installs @tabler/icons-react and motion. With the @uibrik namespace set up: npx shadcn@latest add @uibrik/mitosis-menu.Usage
import { MitosisMenu } from "@/components/uibrik/mitosis-menu/mitosis-menu";<MitosisMenu direction="up" distance={88} spread={150} size={56} optionSize={46} goo={1} stagger={35} bounce={0.3} defaultOpen={false} label="Add" onSelect={(item) => {}} // items={[{ id: "…", label: "…" }]} // open={false} // onOpenChange={(open) => {}}/>Props
MitosisMenu- direction
- Type "up" | "down" | "left" | "right" | "radial"
- "up"
- Which way the options fan out.
- distance
- Type number
- 88
- Distance from the button's centre to each option's.
- spread
- Type number
- 150
- Angle the options fan across. Ignored for radial.
- size
- Type number
- 56
- Diameter of the button.
- optionSize
- Type number
- 46
- Diameter of an option.
- goo
- Type number
- 1
- How thick and stretchy the liquid necks are.
- stagger
- Type number
- 35
- Delay between options budding off.
- bounce
- Type number
- 0.3
- Springiness of the options. 0 settles without overshoot.
- items
- Type { id: string; label: string; icon?: ReactNode }[]
- SAMPLE_OPTIONS
- Options in order.
- onSelect
- Type (item) => void
- –
- Called with the option chosen. The menu closes after.
- open / onOpenChange
- Type boolean / (open) => void
- –
- Controlled open state.
- defaultOpen
- Type boolean
- false
- Start open.
- label
- Type string
- "Add"
- Names the button for screen readers.
- className
- Type string
- –
- Classes for the wrapper.