SplitButton
A compound action button combining a primary action (left) with a dropdown of secondary actions (right chevron). Useful when one action is clearly primary but alternatives must remain accessible.
Overview
SplitButton renders [Button | divider | IconButton] — three DOM nodes inside a single visual unit. The divider is a border-r CSS rule, not a separate DOM element. The IconButton (chevron) toggles an ActionsDropdown portal.
Control open/close state externally via open, onSplitClick, and onDropdownClickAway — SplitButton is uncontrolled by default, so you manage the open state.
Import
import { SplitButton } from '@unflow/ui/components/SplitButton';Props
| Prop | Type | Default | Description |
|---|---|---|---|
label | string | — | Required. Primary button label |
variant | 'primary' | 'secondary' | 'tertiary' | 'destructive' | 'destructiveSecondary' | 'social' | 'primary' | Visual variant |
size | 'xs' | 'sm' | 'md' | 'lg' | 'sm' | Button size |
open | boolean | false | Whether the dropdown is open |
items | ActionsDropdownItem[] | — | Dropdown action items |
onButtonClick | MouseEventHandler | — | Handler for the primary button |
onSplitClick | MouseEventHandler | — | Handler for the chevron (toggle) |
onDropdownClickAway | () => void | — | Called when clicking outside the dropdown |
loading | boolean | false | Loading state |
disabled | boolean | false | Disables both segments |
fullWidth | boolean | false | Full-width layout |
Default
const [open, setOpen] = useState(false);
const items = [
{ label: 'Save as draft', onClick: () => save('draft') },
{ label: 'Save and publish', onClick: () => save('publish'), groupIndex: 1 },
{ label: 'Save and schedule', onClick: () => save('schedule') },
];
<SplitButton
label="Save"
open={open}
items={items}
onButtonClick={() => save('default')}
onSplitClick={() => setOpen((v) => !v)}
onDropdownClickAway={() => setOpen(false)}
/>Variants
<SplitButton label="Primary" variant="primary" ... />
<SplitButton label="Secondary" variant="secondary" ... />Dropdown items
items is an array of ActionsDropdownItem which extends IActionCard. The groupIndex property on consecutive items creates a separator in the dropdown when the index changes between adjacent items.
const items: ActionsDropdownItem[] = [
{ label: 'Save as draft', onClick: handleDraft },
{ label: 'Save and publish', onClick: handlePublish, groupIndex: 1 }, // separator before this
{ label: 'Discard changes', onClick: handleDiscard, groupIndex: 1 },
];Customization (slotProps)
| Slot | Props | Description |
|---|---|---|
button | Partial<IButton> | Override props on the left Button segment |
split | Partial<IIconButton> | Override props on the right chevron IconButton |
actionsDropdown | Omit<IActionsDropdown, 'open' | 'anchorEl' | ...> | Override the dropdown |
loading | ButtonLoadingSlotProps | Loading state config |
Accessibility
- The left Button and right IconButton are separately focusable and keyboard-operable.
- Always provide
aria-labelon the right segment viaslotProps.splitif the chevron purpose isn't obvious:slotProps={{ split: { 'aria-label': 'More save options' } }}. - The ActionsDropdown follows WAI-ARIA
menupattern internally.