SplitButton
A main verb with close relatives.
About
Reach for this when one verb has close variants of the same act: Save, Save and new, Save and send. The main half runs the common case; the chevron opens a menu with the rest. Unrelated actions belong in a sui-menu or a toolbar, not here.
Usage
Basic
items is a property: the shared menu row shape, with icons, shortcuts, badges, danger rows and separators.
Open state
The menu opens under the control, lined up with the edge menu-align names. While open it paints in the top layer, so a card, a scroll box or a transformed parent cannot clip or move it. The chevron carries aria-haspopup="menu", aria-expanded and aria-controls.
Roles and sizes
variant takes accent, brand and outline, and size the same 28, 34 and 42px heights as the rest of the control family. menu-align picks the edge the menu lines up with.
Loading and disabled
Loading spins on the main half, blocks both halves and closes an open menu. Disabled blocks both halves.
Links
A row with href is a real link: suiPick fires and the menu closes on the click, then the browser follows. Keep the verbs in the menu and put the destination on the row that is one.
In a form
Only the main half takes part in the form: type, name, value and form go to it, and the chevron is always type="button", so opening the menu can never submit.
Events
The main half's click is the native host click; the chevron's click never reaches the host. suiOpen fires after the element opens itself, a cancelable suiClose with the reason as detail before it closes itself, and suiPick when a row runs; writing open from outside echoes neither.
Keyboard
| Key | Action |
|---|---|
| Enter Space | On the main half, runs the action. On the chevron, opens or closes the menu. On a row, picks it; on a row with href the browser then follows the link. |
| ArrowDown | On either half, opens the menu and focuses the first row. In the menu, moves to the next row, wrapping past the last. |
| ArrowUp | On either half, opens the menu and focuses the last row. In the menu, moves to the previous row, wrapping past the first. |
| Home End | Move to the first or last row. Disabled rows and separators are skipped. |
| Any letter | Moves to the next row whose label starts with that letter. |
| Escape | Closes the menu and returns focus to the chevron. |
| Tab | In the menu, closes it and moves on to the control after the split button. |
| Shift+Tab | In the menu, closes it and returns focus to the chevron. |
API
<sui-split-button>
Properties
| Property | Attribute | Type | Default | Description |
|---|---|---|---|---|
disabled | disabled | boolean | false | Disables both halves. Reflected. |
form | form | stringstring | undefined | Associates the main half with a form by id, for a split button that sits outside the form it submits: a dialog footer, or a sticky action bar. | |
icon | icon | stringstring | undefined | Font Awesome class for the main half. | |
items | property only | SuiMenuItem[] | [] | Menu rows (shared SuiMenuItem shape: label, icon, shortcut, badge, danger, disabled, separator, section, href, target). A row with href is a real link: Enter follows it, and suiPick fires and the menu closes on the click first. The menu is one level, so a row's nested items are not opened and the row says nothing about them. Property, not attribute. |
label* | label | string | Main verb, e.g. "Save". | |
loading | loading | boolean | false | Shows a spinner on the main half and blocks both halves. Closes the menu if it is open. Reflected. |
menuAlign | menu-align | "end" | "left" | "right" | "start" | 'start' | Which edge of the control the menu lines up with. start and end follow the reading direction, and start is the default, so the menu opens from the control's leading edge in either direction; left and right name sides of the screen, as Ant's placement does. |
menuWidth | menu-width | number | 200 | Width of the menu panel in px. |
name | name | stringstring | undefined | Submitted name of the main half. Pair it with value, or the entry posts empty. | |
open | open | boolean | false | Opens the menu. Mutable: the element closes itself on pick, outside pointer, Tab and Escape, announcing each with a cancelable suiClose, so plain HTML works with no listener at all. It is what you asked for, never rewritten behind your back: a disabled or loading control draws no menu whatever open says, and the menu comes back when the control settles. An open menu paints in the browser's top layer, so a transformed, contained or clipping ancestor cannot move it or cut it off. |
size | size | "lg" | "md" | "sm" | 'md' | Control height: sm 28px, md 34px, lg 42px. Reflected. |
type | type | "button" | "reset" | "submit" | 'button' | Native button type of the main half. submit participates in the surrounding form. Only the main half takes part in a form: type, name, value and form go to it, and the chevron is always type="button", so opening the menu can never submit. |
value | value | stringstring | undefined | Value submitted with the form when the main half submits it. | |
variant | variant | "accent" | "brand" | "outline" | 'accent' | Visual role of both halves. accent = the one primary action per view. |
Events
| Event | Detail | React | Vue | Description |
|---|---|---|---|---|
suiClose | SuiCloseReason"cancel" | "close-button" | "escape" | "outside" | "pick" | "scrim" | "trigger" | onSuiClose | @sui-close | Fires before the element closes the menu itself; detail is why: 'pick' (a row ran), 'trigger' (the chevron was pressed again), 'outside' (a pointer landed elsewhere, or Tab left the menu: focus goes back to the chevron, and Tab carries on to whatever follows the control while Shift+Tab stops on the chevron), 'escape', or 'cancel' (the control went disabled or loading under an open menu). Cancelable: preventDefault() keeps it open, so a parent that binds open never goes stale and "a stray click outside must not close this" needs no prop of its own. On 'cancel' a veto means the menu is hidden while the control is inert and comes back when it settles, because menuOpen and not open alone decides what renders. It does not bubble. |
suiOpen | void | onSuiOpen | @sui-open | Fires after the element opens the menu itself (a chevron press, or ArrowDown/ArrowUp on either half). An external open write does not echo it. It does not bubble. |
suiPick | SuiMenuItem | onSuiPick | @sui-pick | Fires when a menu row is picked; detail is the item. item.command() also runs. The main half's click is the native host click; the chevron's click never reaches the host, so a click listener means the primary action ran and nothing else. |
Methods
| Method | Signature | Description |
|---|---|---|
setFocus() | setFocus() => Promise<void> | Moves keyboard focus to the main button. |
Types
SuiCloseReason typeWhy a dismissible surface is closing. Detail of the cancelable suiClose. A consumer expresses "a stray backdrop click must not close this" by calling preventDefault() on the reason it does not accept, which is why none of these needs a prop of its own. | |||
|---|---|---|---|
| No members. |
SuiMenuItem interface | |||
|---|---|---|---|
label? | string | ||
icon? | string | ||
shortcut? | string | ||
badge? | string | number | ||
danger? | boolean | ||
disabled? | boolean | ||
separator? | boolean | ||
section? | string | Section heading row (uppercase eyebrow). | |
items? | SuiMenuItem[] | Nested items (TieredMenu, Menubar dropdowns). | |
command? | () => void | ||
href? | string | Renders the row as a real link, so middle-click, copy link and open in a new tab work and Enter follows it. The row keeps its styling, its place in the arrow-key order and its pick: command runs and suiPick fires on the click, then the browser navigates. Ignored on a disabled row and on a row with nested items; those stay buttons. | |
target? | string | Link target for a row with href, e.g. _blank. A _blank row gets rel="noopener". | |
current? | boolean | The row is the page the reader is on: it carries aria-current="page" and the bold face sui-side-nav gives its current item. For a navigation menu, the site pages behind a phone menu button; an action menu has no current row. | |
checked? | boolean | Makes the row one choice of a set, for a mode or an order picked from a menu: the chosen row draws a check and every row keeps room for one, and the rows read as menuitemradio with aria-checked. Leave it unset on an action row. | |
Theming
Every design token this element can render with, read from its own stylesheets and the ones it imports. Set a token on :root or on any ancestor and every use below follows it. The values shown are the ones in the theme you are viewing. The list is read per stylesheet, so an element that imports a shared drawing module lists that module's tokens too, whether or not it paints with all of them.
Color27
Typography1
Spacing and size4
Radius1
Elevation2
Motion3
Every name above is listed with its value and its role in Foundations.