Split Button

Pro

Main action joined to a menu of alternatives. Used as a picker, choosing an option swaps the main label in place, and a finished state fuses both halves into one pill with a check.

Preview

Installation

npx @lumioui/cli add pro/split-button

Usage

import { SplitButton } from "@/components/ui/split-button/split-button";
<SplitButton />

Examples

Export

The export bar of a design editor, in ink.

Merge

The merge box at the bottom of a pull request.

Schedule send

The compose sheet of a mail app.

API reference

Prop Type Default
options* SplitButtonOption[]

Menu options.

—
label string

Primary label (actions mode, or select mode before anything is picked).

—
icon React.ReactNode

Leading icon element for the primary segment.

—
value string

Controlled selected option — turns on select mode.

—
defaultValue string

Uncontrolled initial selection — turns on select mode.

—
onValueChange (value: string) => void

Fires when an option is picked in select mode.

—
onSelect (value: string) => void

Fires when a menu item is picked in actions mode.

—
onPress
(value: string | undefined) => void … (value: string | undefined) => void | Promise<unknown>

Primary action. Receives the selected value in select mode. Return a promise for a loading state.

—
variant "default" | "secondary" | "outline"

Visual style. Default "default" (accent/ink fill).

"default"
size "sm" | "md" | "lg"

sm 36 · md 44 · lg 56. Default "md".

"md"
fullWidth boolean

Stretch the primary segment to fill the row.

false
loading boolean

Force the primary segment into its loading state.

—
disabled boolean false
menuLabel string

Accessibility label for the menu segment. Default "More options".

"More options"
open boolean

Controlled menu open state.

—
onOpenChange (open: boolean) => void —
sealed boolean

Commit performed on the object: the segments fuse into one pill, a check draws and the label swaps to sealedLabel, one sheen crosses, then a 700ms hold before onSettled. Presses are blocked while sealed.

false
sealedLabel string

Label on the fused pill. Default "Done".

"Done"
settledLabel string

After the hold, the pill dims to a quiet secondary fill reading this (e.g. "Merged · squash · just now"). Omit to stay on sealedLabel.

—
onSettled () => void

Fires once the sealed result has held.

—
className string —