Split button
One pill with two parts: the main part runs the best move, its chevron opens a menu of the others.
import { SplitButton } from "@arcadia/ui"One pill, two parts. The main part names the best move and runs it; the chevron opens the menu of every other move, the best one first. A 1px divider in the border's ink keeps them apart, each part hovers and presses on its own, and each takes its own focus ring. A hint shows the key that runs the main part from elsewhere.
The main part's label is whole or gone, never faded. With less room than the split needs, the chevron stands alone, labelled menuLabel, and the menu still opens from it: Continue on where the split said Continue on Large model. collapse="menu" keeps that form for a move that has no single best choice, several items at once.
Examples
Variants
The four Button variants a split takes. Both parts share the variant; primary draws its divider in the label's ink.
Collapse
Drag to narrow the room. The split measures the width it needs and stands the chevron alone below it, before it paints, so nothing jumps.
Several items
Moving a group has no single best move: collapse="menu" shows the menu alone at any width.
rootStyle takes where the split sits: margins, self-alignment, flex and grid placement and size bounds. Its look is the Button variant it takes.
Two native <button>s in reading order. The main part is named by its label; the chevron by menuLabel, with aria-haspopup and aria-expanded, and focus moves into the menu and back. Standing alone, the chevron is one button named by the label it shows.
A hint is drawn only and becomes aria-keyshortcuts on the main part; binding the key is yours. busy sets aria-busy on the main part and blocks both parts without dropping focus.
- EnterSpace
- On the main part, run its move
- EnterSpace↓
- On the chevron, open the menu
- Esc
- Close the menu and return focus
SplitButton
onClick- (e: MouseEvent<HTMLButtonElement>) => void
menuLabelrequired- string
- The chevron's accessible name, and its label standing alone.
menurequired- ReactNode
- The
MenuContentthe chevron opens. variant- "primary" | "secondary" | "ghost" | "text"Default "secondary"
size- "xs" | "sm"Default "sm"
collapse- "auto" | "menu"Default "auto"
auto: the chevron stands alone when the split doesn't fit.menu: always.busy- booleanDefault false
- The main part keeps its width, a spinner takes the chevron's place, both parts are inert.
disabled- booleanDefault false
hold- booleanDefault true
- The label and its action hold while the pointer is on the control or the menu is open.
open- boolean
defaultOpen- booleanDefault false
onOpenChange- (open: boolean, details: OpenChangeDetails) => void
rootStyle- RootStyle
- A component's typed override prop:
Layoutplus the knobs it documents.Knobsmaps each knob to the references it takes ({ "--button-px": Ref<Space> }), so a literal colour, a wrong-kind token or a property the component doesn't expose is a type error at the call site. A knob also takes another kit knob of the same kind ("--icon-size": "var(--button-icon)"). childrenrequired- ReactNode
- The main part's label: whole or gone, never faded.
Rest props go to <span> props.