SplitButton
A button combining a primary action with a dropdown for secondary options. Use when one action is clearly dominant but related alternatives are available. Don't use when actions are equally weighted — use ButtonGroup instead.
FigmaDescription
Presents a primary action as a labelled button alongside a small chevron trigger that opens a dropdown menu of related secondary actions. Clicking the main label fires the primary action immediately; clicking the chevron reveals alternatives without committing to anything.
Record-level toolbars in Open Point (e.g. a stakeholder profile header, a consultation record action bar) and in data-table row actions where one action dominates — for example Save as Draft vs Save and Publish vs Save and Notify.
Government workflows frequently have a clear primary path (submit, publish, approve) alongside less-frequent but contextually related alternatives (save draft, schedule, export). Surfacing all options as equal buttons adds visual noise and slows task completion. The split button preserves hierarchy while keeping alternatives discoverable without a full overflow menu.
Anatomy
| Part | Required? | Notes |
|---|---|---|
| Primary action segment | Required | A standard button label that fires the primary action on click. Inherits all button variants (primary, secondary, danger). Width grows with label length. |
| Divider | Required | A 1px vertical rule separating the primary segment from the chevron segment. Uses --op-color-border-default at reduced opacity so it reads as internal structure, not a boundary. |
| Chevron trigger segment | Required | A fixed-width (36px minimum, 44px touch) segment containing a downward-pointing chevron icon. Activates the dropdown on click or Enter/Space. Has its own focus state, hover state, and active state independent of the primary segment. |
| Dropdown menu | Required | A DropdownMenu panel anchored below the chevron segment. Contains secondary action items. Should include 2–5 items; more than 5 items indicates the component is being misused. |
| Dropdown item | Required | Each item in the dropdown. May include a leading icon for differentiation. Destructive items use --op-color-status-error and appear last, separated by a divider. |
| Focus ring | Required | 3px solid --op-color-interactive-focus. Applied independently to the primary segment and to the chevron segment — both are separately focusable and both display the ring. |
Variants
Primary
High-emphasis affirmative action (green fill)
The dominant action is the recommended or most common path — e.g. 'Publish' on a consultation record.
Secondary
Medium-emphasis action (outlined, no fill)
The primary action is important but not the single recommended path — e.g. 'Export' where multiple formats are available.
Danger
Destructive or irreversible primary action (red fill)
The dominant action itself is destructive — e.g. 'Archive' with alternatives like 'Archive and Notify' or 'Archive All'. Use sparingly; confirm via dialog before executing.
States
| State | Behaviour |
|---|---|
| Default | Primary segment and chevron segment render at rest. Divider visible. Dropdown hidden. |
| Primary segment — hover | Primary segment background lightens to --op-color-interactive-hover. Chevron segment unchanged. Cursor is pointer. |
| Chevron segment — hover | Chevron segment background lightens to --op-color-interactive-hover. Primary segment unchanged. |
| Primary segment — focus | 3px focus ring on primary segment only. Keyboard Enter or Space fires the primary action. |
| Chevron segment — focus | 3px focus ring on chevron segment only. Keyboard Enter, Space, or ArrowDown opens the dropdown. |
| Open (dropdown visible) | Chevron rotates 180deg (if motion permitted). Dropdown panel appears below chevron segment. First dropdown item receives focus. Clicking outside or pressing Escape closes the dropdown and returns focus to the chevron segment. |
| Disabled | Both segments are non-interactive. Opacity 40% (--op-color-interactive-default at 0.4). Cursor is not-allowed. The entire component, including the chevron trigger, is inert. No dropdown can be opened. |
| Loading | Primary segment shows a wa-spinner replacing the label. Chevron segment is disabled until the primary action resolves. Used when the primary action triggers an async operation (e.g. publishing a consultation). |
Usage guidelines
When to use
- One action is clearly dominant and users will choose it the majority of the time — the label should reflect that dominant action.
- Secondary actions are related to the same object or workflow — e.g. all variants of saving or publishing a record.
- Screen space is constrained and showing all actions as separate buttons would cause toolbar overflow.
- The dropdown contains 2–5 alternatives, not a full action menu.
When not to use
- Actions are equally weighted — use ButtonGroup instead so no false hierarchy is implied.
- There is only one action available — use a standard Button.
- The dropdown would contain more than five items — use an OverflowMenu or restructure the workflow.
- The primary action is unclear or changes depending on context — use an explicit ButtonGroup or DropdownMenu with a neutral trigger.
- You need inline actions inside a data table cell — use an IconButton or RowActionMenu instead to preserve row height.
Do / Don't
Do
Label the primary segment with a specific verb that describes the dominant action: 'Publish', 'Send', 'Approve'.
Don't
Use vague labels like 'Actions' or 'Options' — those belong on a plain DropdownMenu trigger, not a split button.
Do
Keep dropdown items contextually related to the primary action — variants of the same operation.
Don't
Mix unrelated actions in the dropdown (e.g. 'Delete' alongside 'Export as CSV') — this creates confusion about the action group's purpose.
Do
Place destructive dropdown items last, after a visual divider, and label them clearly (e.g. 'Archive and Delete All Responses').
Don't
Lead with destructive items or mix them among neutral items without separation.
Do
Disable the entire component (both segments) when the user lacks permission to perform any of the actions.
Don't
Disable only the primary segment and leave the chevron active — this implies alternatives are available when they should also be restricted.
Layout & Spacing
Component height: 40px (default), 32px (sm), 48px (lg) — matching Button size tokens. Primary segment padding: 0 --op-space-16 (0 16px). Divider: 1px wide, full height minus --op-space-8 (8px) top and bottom inset. Chevron segment width: 36px minimum; 44px on touch breakpoints to meet minimum touch target. Gap between primary label and left edge: --op-space-16. Dropdown panel margin-top: --op-space-4 (4px) from component bottom edge. Dropdown item padding: --op-space-8 --op-space-16 (8px 16px). Dropdown item row gap (icon + label): --op-space-8 (8px). Border radius on component: --op-radius-md (8px) — applied to outer corners only; divider area has no radius.
Tokens
| Part | Token | Value |
|---|---|---|
| Primary segment background (primary variant) | --op-color-interactive-default | green-400; hover state uses --op-color-interactive-hover |
| Primary segment text (primary variant) | --op-color-text-on-interactive | White text on green; must meet 4.5:1 contrast |
| Primary segment background (secondary variant) | --op-color-bg-primary | Transparent/white fill; border uses --op-color-border-default |
| Primary segment text (secondary variant) | --op-color-text-primary | Dark text on light background |
| Primary segment background (danger variant) | --op-color-status-error | Red fill for destructive primary action |
| Divider | --op-color-border-default | At 60% opacity to read as internal structure |
| Chevron icon | --op-color-text-on-interactive | Inherits from parent variant text colour |
| Focus ring | --op-color-interactive-focus | 3px solid, offset 2px, applied to each segment independently |
| Dropdown panel background | --op-color-bg-primary | Surface white; shadow uses elevation token if defined |
| Dropdown panel border | --op-color-border-default | 1px solid |
| Dropdown item text | --op-color-text-primary | Default; destructive items use --op-color-status-error |
| Dropdown item hover background | --op-color-bg-secondary | Subtle fill on hover/focus |
| Disabled state overlay | --op-color-interactive-default | At 40% opacity across entire component |
Engineering notes
- The split button is not a single Web Awesome primitive. Compose it from a wa-button-group wrapping two wa-button elements, paired with a wa-dropdown anchored to the chevron button.
- The chevron wa-button must have aria-haspopup='menu' and aria-expanded toggled programmatically when the dropdown opens and closes.
- Use aria-controls on the chevron button pointing to the dropdown menu's id so assistive technology can navigate the relationship.
- The primary segment and the chevron segment must each be individually focusable (tabindex='0' on both). Do not merge them into a single focusable element.
- Manage keyboard navigation inside the dropdown with roving tabindex or aria-activedescendant — do not let Tab move through dropdown items; use ArrowUp/ArrowDown.
- On Escape from an open dropdown, close the panel and return focus explicitly to the chevron button using .focus().
- Respect prefers-reduced-motion: only apply the chevron rotation transform when the user has not opted out of motion.
- For the loading state, replace the primary segment label slot with a wa-spinner and set aria-label on the button to describe the in-progress action (e.g. 'Publishing consultation, please wait').
- Token-based sizing: apply component height via a CSS custom property (--split-btn-height) derived from the design token scale so all three sizes (sm, default, lg) can be toggled with a single attribute.
Keyboard interaction
| Key | Action |
|---|---|
| Tab | Moves focus to the primary segment. A second Tab press moves focus to the chevron segment. A third Tab press moves focus out of the component. |
| Enter / Space (primary segment focused) | Fires the primary action immediately. Does not open the dropdown. |
| Enter / Space / ArrowDown (chevron segment focused) | Opens the dropdown menu. Focus moves to the first non-disabled dropdown item. |
| ArrowDown (dropdown open) | Moves focus to the next dropdown item, wrapping to the first item after the last. |
| ArrowUp (dropdown open) | Moves focus to the previous dropdown item, wrapping to the last item from the first. |
| Enter / Space (dropdown item focused) | Executes the focused dropdown item's action and closes the dropdown. |
| Escape (dropdown open) | Closes the dropdown without performing any action. Returns focus to the chevron segment. |
| Home (dropdown open) | Moves focus to the first dropdown item. |
| End (dropdown open) | Moves focus to the last dropdown item. |
Why it matters
Government digital services are used by staff with diverse accessibility needs — including keyboard-only operators in call centres and screen reader users in field teams. A split button that traps focus, lacks ARIA labelling, or conflates two actions into one focusable element will be unusable for these staff. Compliance with WCAG 2.1 AA is a baseline legal requirement for Australian Government services and a contractual requirement for Openpoint customers.
Focus
Each segment — primary and chevron — is a discrete focusable element. They appear in source order so Tab moves left to right. Neither segment is skipped when the dropdown is open; the dropdown items form their own focus scope and do not enter the main Tab sequence. When the dropdown closes (via Escape, item selection, or outside click), focus returns to the chevron segment, not the primary segment, because the chevron was the trigger. The focus ring is always visible — it is never suppressed on click for mouse users, as government environments include users who switch between input modalities mid-task.
ARIA
| Role or attribute | When to use | Example |
|---|---|---|
role='group' | Applied to the outer container element to group the primary button and chevron button as a logical unit. | <div role="group" aria-label="Publish consultation"> |
aria-label (outer group) | Names the overall action group. Should match the primary action label so screen readers announce context before individual buttons. | aria-label="Publish consultation" |
aria-haspopup='menu' | Applied to the chevron button to indicate it opens a menu. | <wa-button aria-haspopup="menu" aria-expanded="false" aria-controls="split-btn-menu-1"> |
aria-expanded | Toggled on the chevron button: false when closed, true when open. Updated programmatically. | aria-expanded="true" |
aria-controls | On the chevron button, references the id of the dropdown menu element. | aria-controls="split-btn-menu-1" |
role='menu' | Applied to the dropdown panel. | <ul role="menu" id="split-btn-menu-1"> |
role='menuitem' | Applied to each item inside the dropdown. | <li role="menuitem">Save as Draft</li> |
aria-label (chevron button) | Provides a visible-context-free label for the chevron segment since it has no text. Describe what opening it reveals. | aria-label="More publish options" |
aria-disabled='true' | Used instead of the disabled HTML attribute when you need the element to remain focusable but inert (e.g. to allow tooltip explanation of why it is disabled). | aria-disabled="true" |
Contrast
Primary variant: --op-color-text-on-interactive (white) on --op-color-interactive-default (green-400). Must achieve 4.5:1 for normal text. Verify at the specific green-400 hex value — if the primitive ramp does not meet ratio, escalate to the design token owner before shipping. Secondary variant: --op-color-text-primary on --op-color-bg-primary. Typically dark-on-white; verify ratio is at least 4.5:1. Danger variant: --op-color-text-on-interactive (white) on --op-color-status-error. Verify; some red tokens fail at 4.5:1 against white — check and adjust if needed. Dropdown items: --op-color-text-primary on --op-color-bg-primary — standard body contrast, should pass comfortably. Destructive dropdown items: --op-color-status-error on --op-color-bg-primary — red text on white; verify meets 4.5:1. If not, use a darker error token. Disabled state at 40% opacity: contrast will fail by design. This is acceptable per WCAG 2.1 SC 1.4.3 exception for disabled controls, provided the disabled state is clearly communicated by means other than colour alone.
Touch targets
The chevron segment must be at least 44x44px on touch breakpoints. Because the primary segment is typically wider than 44px, it naturally meets the target. Use CSS to enforce min-width: 44px and min-height: 44px on the chevron segment. Do not reduce the chevron segment below 36px on desktop — below this width the icon becomes difficult to click accurately with a mouse.
Things to avoid
- Do not make the entire split button a single focusable element — both segments must be individually reachable by keyboard.
- Do not use title attributes as the sole accessible label for the chevron — title tooltips are not reliably announced by screen readers and are invisible to keyboard users.
- Do not dismiss the dropdown on blur without checking whether focus moved to a dropdown item — this causes the menu to close before users can select from it.
- Do not apply aria-expanded to the primary segment — it has no popup and the attribute would be misleading.
- Do not render dropdown items as anchor tags unless they navigate to a new URL. Use button elements for actions; reserve anchors for navigation.