HySplitButton
Usage examples on this page are written for Lit / plain HTML (
<hy-split-button>). The same component ships asHySplitButtonin@whitespaceux/harmony-react(native React 19), with typed wrappers for Angular, Solid, Svelte, and Vue. The API reference below applies to all frameworks.
A main action and a chevron that opens a menu of related actions, joined into one control ("Save ▾" — Save as…, Save a copy). Composes two hy-buttons and an hy-menu-button; it adds the joined geometry, the seam between the segments and one variant / emphasis / size / disabled for both.
Key Features
- Two real buttons, two Tab stops: the main action and a menu button named by
menu-label("More save options") - Inner corners square, outer corners the design system's button corners
- The seam is geometry: a shared border when outlined, a hairline gap otherwise
- The menu takes
hy-menu-button's items,actions,select/change,show/hide - Inside
hy-toolbarboth segments are arrow stops of the toolbar
Split button or menu button?
A split button when one action is the usual choice and the menu holds its variations; hy-menu-button when no action is the default, so nobody runs the wrong one by habit. Keep destructive actions off the main segment.
Events
The main action fires activate — a plain click on the host can't tell the two segments apart. Menu items fire select (and change for radio groups).
When to use
- A main action that has a few variations people sometimes need: Save, with Save as… and Save a copy.
- A default choice most people take, with the alternatives one click away.
Do
- Put the most used variation on the main part.
- Keep the menu to variations of the same action.
When not to use
- Only one action:
hy-button. - Actions that are not variations of one another, such as Save and Delete: separate
hy-buttons, or a button and ahy-menu-button. - Picking a value a form reads, such as a format:
hy-selectorhy-combobox.
Examples
Save with more save options
<hy-split-button label="Save" menu-label="More save options" variant="brand">
<hy-menu-item value="save-as" label="Save as…"></hy-menu-item>
<hy-menu-item value="save-copy" label="Save a copy"></hy-menu-item>
</hy-split-button>API
Properties
| Property | Attribute | Type | Default | Description |
|---|---|---|---|---|
label | label | string | '' | The main action's visible text. Required. |
menuLabel | menu-label | string | 'More options' | The chevron segment's accessible name — name the action ("More save options"). |
variant | variant | 'neutral' | 'brand' | 'success' | 'warning' | 'danger' | 'info' | 'highlight' | 'neutral' | Semantic role of both segments — hy-button's role set. |
emphasis | emphasis | 'solid' | 'soft' | 'outlined' | 'tinted' | 'solid' | Visual chrome weight of both segments. No plain (it renders outlined, with a dev warning). |
size | size | 'small' | 'medium' | 'large' | 'medium' | Size of both segments; the menu takes small or medium. |
disabled | disabled | boolean | false | Disables both segments. |
loading | loading | boolean | false | The main action is busy: its spinner shows, and both segments are inert. |
loadingText | loading-text | string | 'Loading' | Text announced while loading — passed to the main action's hy-button loading-text. Use for internationalization. |
type | type | 'button' | 'submit' | 'reset' | 'button' | What the main action does in a form. The chevron never submits. |
form | form | string | undefined | — | The id of the form a submit or reset main action acts on when the split button sits outside it — a dialog footer, a toolbar — as hy-button's form. Unset, the main action acts on the form it is inside. The host is form-associated, so the browser resolves it (internals.form). |
placement | placement | 'top' | 'top-start' | 'top-end' | 'bottom' | 'bottom-start' | 'bottom-end' | 'left' | 'left-start' | 'left-end' | 'right' | 'right-start' | 'right-end' | 'bottom-end' | Where the menu opens, relative to the chevron. |
width | width | string | '' | Fixed menu-panel width (any CSS length). |
minWidth | min-width | string | '' | Minimum menu-panel width. |
open | open | boolean | false | Controlled menu state. |
actions | — | MenuAction[] | [] | Items from data, when the default slot is empty — slotted items win. |
fullWidth | full-width | boolean | false | The main segment grows to fill the host; the chevron keeps its width. |
Events
| Event | Detail | Description |
|---|---|---|
activate | — | The main action was clicked or pressed. Detail: HyClickDetail |
select | — | A menu item was chosen (relayed from the menu). Detail: MenuSelectDetail |
change | — | A menu radio group changed (relayed). Detail: MenuChangeDetail |
show | — | The menu opened (does not bubble) |
hide | — | The menu closed (does not bubble) |
Slots
| Slot | Description |
|---|---|
default | hy-menu-item / hy-menu-item-checkbox / hy-menu-item-radio / hy-menu-group / hy-divider children |
prefix | An icon before the main action's label |
CSS Parts
| Part | Description |
|---|---|
base | The wrapper around the two segments |
primary | The main action (hy-button) |
trigger | The chevron segment (hy-button) |
CSS Custom Properties
The documented hooks. Every override hook the component reads — one per token it paints — is listed in @whitespaceux/harmony/theme-api.json, and @whitespaceux/harmony/component-bindings.json (the Harmony MCP get-bindings tool) says which part and state each one paints.
| Property | Default | Description |
|---|---|---|
--hy-split-button-stroke-sm | var(--hy-stroke-sm) | The seam: the gap between the segments (solid, soft, tinted) or their shared border (outlined) |
--hy-split-button-effect-glow | on | The glow around the whole control (solid brand and highlight); the segments draw none |
--hy-split-button-radius-action-md-top-start | var(--hy-radius-action-md-top-start) | The control's outer corner the glow follows (top-start; also top-end, bottom-start, bottom-end) |
Methods
focus()
Focuses the main action.