Skip to content

Conversation

@mgadewoll
Copy link
Contributor

@mgadewoll mgadewoll commented Dec 11, 2025

Summary

closes #8942

Note

The component was initially PoC'd here and is currently implemented as custom component on Kibana side here.

This PR introduces a new component to EUI: EuiSplitButton. This component provides its two specialized children components as sub-components EuiSplitButton.ActionPrimary and EuiSplitButton.ActionSecondary. These inherit from EuiButton and EuiButtonIcon respectively and define expected behaviors. However, EuiSplitButton controls a few props across both sub-components, overriding the sub-component props: color, size, fill.

Screenshot 2025-12-15 at 10 03 16

API

EuiSplitButton

prop type default value description
children [<EuiSplitButton.ActionPrimary>, <EuiSplitButton.ActionSecondary>] undefined Defines the actual action buttons as React components
color EuiButtonProps['color'] primary Defines the color variant for both action buttons
size EuiButtonProps['size'] m Defines the button size for both action buttons
fill EuiButtonProps['fill'] false Defines the filled color variant for both action buttons
isDisabled EuiDisabledProps['isDisabled] false Defines the disabled state for both action buttons
isLoading EuiButtonProps['isLoading] false Defines the loading state for both action buttons

EuiSplitButton.ActionPrimary (inherits props from EuiButton or EuiButtonIcon (depending on isIconOnly))

prop type default value description
isIconOnly boolean false Defines if the primary action button is rendered as EuiButtonIcon
tooltipProps EuiToolTipProps undefined Renders an EuiToolTip around the action button and passes along the tooltip props

EuiSplitButton.ActionSecondary ( inherits props from EuiButtonIcon)

prop type default value description
tooltipProps EuiToolTipProps undefined Renders an EuiToolTip around the action button and passes along the tooltip props
popoverProps EuiPopoverProps undefined Renders an EuiPopover around the action button and passes along the popover props

Why are we making this change?

✨ Serving feature request: Providing a new component based on feature requests on Kibana side.

Screenshots #

default

Light Dark
Screenshot 2025-12-15 at 10 16 54 Screenshot 2025-12-15 at 10 16 51
tooltip popover
Screenshot 2025-12-11 at 18 21 44 Screenshot 2025-12-11 at 18 21 50
Light Dark
Screenshot 2025-12-12 at 10 20 42 Screenshot 2025-12-12 at 10 20 54

high contrast mode (prefers-contrast)

Light Dark
Screenshot 2025-12-12 at 10 20 48 Screenshot 2025-12-12 at 10 21 01

Windows high contrast themes (forced-colors)

Light Dark
Screenshot 2025-12-12 at 10 21 18 Screenshot 2025-12-12 at 10 21 11

Impact to users

🟢 No updates required. This is a new feature.

ℹ️ The new component was tested as stand-in replacement for the custom implementation in Kibana here

before after
Screenshot 2025-12-12 at 11 15 40 Screenshot 2025-12-12 at 11 02 28

QA

📖 Documentation

  • test the new component API, verify all props work as expected (Story)
  • verify the component renders as expected by design specs 🔒 (Story)

General checklist

  • Browser QA
    • Checked in both light and dark modes
    • Checked in both MacOS and Windows high contrast modes
    • Checked in mobile
    • Checked in Chrome, Safari, Edge, and Firefox
    • Checked for accessibility including keyboard-only and screenreader modes
  • Docs site QA
  • Code quality checklist
  • Release checklist
    • A changelog entry exists and is marked appropriately
    • If applicable, added the breaking change issue label (and filled out the breaking change checklist)
    • If the changes unblock an issue in a different repo, smoke tested carefully (see Testing EUI features in Kibana ahead of time)
  • Designer checklist
    • If applicable, file an issue to update EUI's Figma library with any corresponding UI changes. (This is an internal repo, if you are external to Elastic, ask a maintainer to submit this request)

@mgadewoll mgadewoll self-assigned this Dec 11, 2025
@mgadewoll mgadewoll requested a review from JoseLuisGJ December 11, 2025 17:32
@mgadewoll mgadewoll force-pushed the feat/8942-split-button branch from ece7064 to 646eb83 Compare December 12, 2025 09:31
@mgadewoll mgadewoll marked this pull request as ready for review December 12, 2025 10:23
@mgadewoll mgadewoll requested a review from a team as a code owner December 12, 2025 10:23
@JoseLuisGJ
Copy link
Contributor

JoseLuisGJ commented Dec 12, 2025

Looks great @mgadewoll ! One concern I've is to don't lock the icon to arrowDown into the EuiSplitButton.ActionSecondary when we want to list a subset of secondary actions in a Popover. I'd avoid to let make non consistent combinations like this one:

CleanShot 2025-12-12 at 17 00 25@2x

Could we override the iconType="arrowDown" whenever we provide some value to the popoverProps for instance or any other approach?

And maybe also the other way around, could we avoid to use the arrowDown icon if we hare providing only one action to the EuiSplitButton.ActionSecondary and not displaying a Popover?

@JoseLuisGJ
Copy link
Contributor

We should also show some examples in the Docs and Storybook when the EuiSplitButton.ActionSecondary has only 1 action and will not display a Popover to get a better sense of the use cases we can manage with this new component. This example could work:

CleanShot 2025-12-12 at 17 10 51@2x

@mgadewoll
Copy link
Contributor Author

mgadewoll commented Dec 12, 2025

Could we override the iconType="arrowDown" whenever we provide some value to the popoverProps for instance or any other approach?

@JoseLuisGJ
Yes, we can set fixed arrowDown if popoverProps are passed 👍

And maybe also the other way around, could we avoid to use the arrowDown icon if we hare providing only one action to the EuiSplitButton.ActionSecondary and not displaying a Popover?

For this case, I'd not advise to prevent passing arrowDown but instead handle this with guidance/documentation.
If we simply prevent passing the icon, then nothing would be output, which might be confusing. We could add a development-mode-only console warning, though this seems a bit excessive just for an icon 🤷‍♀️. Imho, proper guidance should be enough.

@acstll acstll self-requested a review December 16, 2025 14:25
@tkajtoch tkajtoch self-requested a review December 16, 2025 15:50
Copy link
Contributor

@acstll acstll left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only a few suggestions, almost all non-blocking and most of them regarding the docs. Awesome implementation, thank you @mgadewoll

Comment on lines +164 to +167
export const EuiSplitButton = Object.assign(_EuiSplitButton, {
ActionPrimary: EuiSplitButtonActionPrimary,
ActionSecondary: EuiSplitButtonActionSecondary,
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[no action required] I really like this pattern, hopefully we can discuss using this more moving forward?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, let's open that as general discussion for further future features/refactors. We could either do it async or as part of a weekly. 👍

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Neat! I love how easy Object.assign makes the type to resolve correctly 🎉

);

return popoverProps ? (
<EuiPopover anchorPosition="downCenter" {...popoverProps} button={action} />
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[non-blocking] since we don't have the arrows anymore, I would make this downRight / @JoseLuisGJ @ryankeairns what do you think?

Suggested change
<EuiPopover anchorPosition="downCenter" {...popoverProps} button={action} />
<EuiPopover anchorPosition="downRight" {...popoverProps} button={action} />

@mgadewoll mgadewoll requested a review from acstll December 18, 2025 10:05
Copy link
Contributor

@acstll acstll left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Awesome work, thanks a lot for addressing my comments!

I left a couple more of non-blocking suggestion. Approving now anyways. Also let's wait for @tkajtoch's review.

@mgadewoll mgadewoll force-pushed the feat/8942-split-button branch from 7830648 to 83bccc3 Compare December 18, 2025 14:04
Copy link
Member

@tkajtoch tkajtoch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new split button component looks really nice ✨ I love the way you implemented it!

I confirmed all props work as expected and match the design spec.

I left a couple small comments. LMK what you think!

Copy link
Member

@tkajtoch tkajtoch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's go!

@elasticmachine
Copy link
Collaborator

💚 Build Succeeded

History

cc @mgadewoll

@elasticmachine
Copy link
Collaborator

elasticmachine commented Dec 19, 2025

💚 Build Succeeded

History

cc @mgadewoll

@mgadewoll mgadewoll merged commit a54de8d into elastic:main Dec 19, 2025
5 checks passed
weronikaolejniczak added a commit to elastic/kibana that referenced this pull request Jan 14, 2026
## Dependency updates

- `@elastic/eui`: `v111.0.0` ⏩ `v111.1.0`
- `@elastic/eui-theme-borealis`: `v5.2.0` ⏩ `v5.3.0`

---

## Changes

- Removed `euiBasicTable.tableCaptionWithPagination`,
`euiBasicTable.tableAutoCaptionWithPagination`,
`euiBasicTable.tableSimpleAutoCaptionWithPagination`,
`euiBasicTable.tableAutoCaptionWithoutPagination` i18n tokens
- Added `euiBasicTable.caption.itemCountPart.withTotalItemCount`,
`euiBasicTable.caption.paginationPart.withPageCount`,
`euiBasicTable.caption.tableName`, `euiBasicTable.caption.emptyState`
i18n tokens
- Updated snapshot tests
- Updated a couple of Jest assertions due to [this EUI
change](https://github.com/elastic/eui/pull/9254/changes)), see
127ab80

## Package updates

### `@elastic/eui`
[v111.1.0](https://github.com/elastic/eui/releases/tag/v111.1.0)

- Added `dashedCircle` icon
([#9278](elastic/eui#9278))
- Added `crossProjectSearch` icon
([#9275](elastic/eui#9275))
- Added component token `components.tourStepIndicatorInactiveColor` and
`components.tourStepIndicatorActiveColor`
([#9271](elastic/eui#9271))
- Remapped `EuiBeacon` component `success` variant to use `success`
color token instead of `accentSecondary`
([#9271](elastic/eui#9271))
- Added `EuiSplitButton` and its respective sub-components
`EuiSplitButton.ActionPrimary` and `EuiSplitButton.ActionSecondary`
([#9269](elastic/eui#9269))
- Added `productRobot` icon
([#9259](elastic/eui#9259))
- Added beta `euiContainer()`, `euiContainerCSS()`, and
`euiContainerQuery()` Emotion utilities to help work with CSS Container
Queries ([#9264](elastic/eui#9264))
- Added `useEuiContainerQuery` hook to observe container query changes
in JavaScript ([#9251](elastic/eui#9251))
- Updated EuiFlexGroup's `gutterSize` from `l` to `m`
([#9132](elastic/eui#9132))
- Updated EuiSpacer's `size` from `l` to `m`
([#9132](elastic/eui#9132))
- Updated EuiHorizontalRule's `margin` from `l` to `m`
([#9132](elastic/eui#9132))
- Updated EuiPageHeader's tab `size` from `l` to `m`
([#9132](elastic/eui#9132))
- Updated EuiEmptyPrompt's spacer `size` between title and text from `m`
to `s` ([#9132](elastic/eui#9132))
- Updated EuiSearchBar's `gutterSize` from `m` to `s`
([#9132](elastic/eui#9132))

<img width="2158" height="392" alt="image"
src="https://github.com/user-attachments/assets/e217f5a5-5b4f-48df-830d-a60861939945"
/>
<img width="1692" height="608" alt="image"
src="https://github.com/user-attachments/assets/d1f49e86-ad8c-4d80-9d02-54c73baae616"
/>
<img width="2182" height="302" alt="image"
src="https://github.com/user-attachments/assets/295c768c-a2df-48f5-80cb-1a1ce5b19e00"
/>
<img width="1904" height="1066" alt="image"
src="https://github.com/user-attachments/assets/f96cbde6-0529-4f5b-be5b-b56f28c5d2b7"
/>
<img width="1566" height="128" alt="image"
src="https://github.com/user-attachments/assets/be4df105-9e32-4a9d-89f0-fe973f441495"
/>

**Bug fixes**

- Fixed flyout overlay masks not being visible for `EuiDataGrid`'s
fullscreen mode by reducing the `z-index` of the fullscreen mode overlay
([#9267](elastic/eui#9267))

**Accessibility**

- Added information about the empty state of `EuiBasicTable` in the
table caption ([#9265](elastic/eui#9265))
- Improved `EuiBasicTable` accessibility by ensuring a fallback
`tableCaption` is applied if none is provided
([#9254](elastic/eui#9254))

### `@elastic/eui-theme-borealis` v5.3.0

- Added component token `components.tourStepIndicatorInactiveColor` and
`components.tourStepIndicatorActiveColor`
([#9271](elastic/eui#9271))
smith pushed a commit to smith/kibana that referenced this pull request Jan 16, 2026
## Dependency updates

- `@elastic/eui`: `v111.0.0` ⏩ `v111.1.0`
- `@elastic/eui-theme-borealis`: `v5.2.0` ⏩ `v5.3.0`

---

## Changes

- Removed `euiBasicTable.tableCaptionWithPagination`,
`euiBasicTable.tableAutoCaptionWithPagination`,
`euiBasicTable.tableSimpleAutoCaptionWithPagination`,
`euiBasicTable.tableAutoCaptionWithoutPagination` i18n tokens
- Added `euiBasicTable.caption.itemCountPart.withTotalItemCount`,
`euiBasicTable.caption.paginationPart.withPageCount`,
`euiBasicTable.caption.tableName`, `euiBasicTable.caption.emptyState`
i18n tokens
- Updated snapshot tests
- Updated a couple of Jest assertions due to [this EUI
change](https://github.com/elastic/eui/pull/9254/changes)), see
elastic@127ab80

## Package updates

### `@elastic/eui`
[v111.1.0](https://github.com/elastic/eui/releases/tag/v111.1.0)

- Added `dashedCircle` icon
([elastic#9278](elastic/eui#9278))
- Added `crossProjectSearch` icon
([elastic#9275](elastic/eui#9275))
- Added component token `components.tourStepIndicatorInactiveColor` and
`components.tourStepIndicatorActiveColor`
([elastic#9271](elastic/eui#9271))
- Remapped `EuiBeacon` component `success` variant to use `success`
color token instead of `accentSecondary`
([elastic#9271](elastic/eui#9271))
- Added `EuiSplitButton` and its respective sub-components
`EuiSplitButton.ActionPrimary` and `EuiSplitButton.ActionSecondary`
([elastic#9269](elastic/eui#9269))
- Added `productRobot` icon
([elastic#9259](elastic/eui#9259))
- Added beta `euiContainer()`, `euiContainerCSS()`, and
`euiContainerQuery()` Emotion utilities to help work with CSS Container
Queries ([elastic#9264](elastic/eui#9264))
- Added `useEuiContainerQuery` hook to observe container query changes
in JavaScript ([elastic#9251](elastic/eui#9251))
- Updated EuiFlexGroup's `gutterSize` from `l` to `m`
([elastic#9132](elastic/eui#9132))
- Updated EuiSpacer's `size` from `l` to `m`
([elastic#9132](elastic/eui#9132))
- Updated EuiHorizontalRule's `margin` from `l` to `m`
([elastic#9132](elastic/eui#9132))
- Updated EuiPageHeader's tab `size` from `l` to `m`
([elastic#9132](elastic/eui#9132))
- Updated EuiEmptyPrompt's spacer `size` between title and text from `m`
to `s` ([elastic#9132](elastic/eui#9132))
- Updated EuiSearchBar's `gutterSize` from `m` to `s`
([elastic#9132](elastic/eui#9132))

<img width="2158" height="392" alt="image"
src="https://github.com/user-attachments/assets/e217f5a5-5b4f-48df-830d-a60861939945"
/>
<img width="1692" height="608" alt="image"
src="https://github.com/user-attachments/assets/d1f49e86-ad8c-4d80-9d02-54c73baae616"
/>
<img width="2182" height="302" alt="image"
src="https://github.com/user-attachments/assets/295c768c-a2df-48f5-80cb-1a1ce5b19e00"
/>
<img width="1904" height="1066" alt="image"
src="https://github.com/user-attachments/assets/f96cbde6-0529-4f5b-be5b-b56f28c5d2b7"
/>
<img width="1566" height="128" alt="image"
src="https://github.com/user-attachments/assets/be4df105-9e32-4a9d-89f0-fe973f441495"
/>

**Bug fixes**

- Fixed flyout overlay masks not being visible for `EuiDataGrid`'s
fullscreen mode by reducing the `z-index` of the fullscreen mode overlay
([elastic#9267](elastic/eui#9267))

**Accessibility**

- Added information about the empty state of `EuiBasicTable` in the
table caption ([elastic#9265](elastic/eui#9265))
- Improved `EuiBasicTable` accessibility by ensuring a fallback
`tableCaption` is applied if none is provided
([elastic#9254](elastic/eui#9254))

### `@elastic/eui-theme-borealis` v5.3.0

- Added component token `components.tourStepIndicatorInactiveColor` and
`components.tourStepIndicatorActiveColor`
([elastic#9271](elastic/eui#9271))
weronikaolejniczak pushed a commit to weronikaolejniczak/eui that referenced this pull request Jan 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[EuiSplitButton] Implement new split button component

5 participants