Skip to content

Conversation

@weronikaolejniczak
Copy link
Contributor

@weronikaolejniczak weronikaolejniczak commented Oct 14, 2025

Summary

Changes:

  • adds an internal focus trap PubSub service,
  • publishes the event from EuiPopover on opening, closing and unmounting the component,
  • subscribes to the event in EuiFlyout, re-queries and updates the focusTrapShards.

Why are we making this change?

Resolves #9099

tl;dr;

To fix keyboard navigation for elements that show up later than the flyout renders and so are not queried statically with includeSelectorInFocusTrap.

More context

The includeSelectorInFocusTrap option was originally introduced to support the grid layout and ensure it works correctly with the flyout:

The issue is that the Side Nav popovers appear after the flyout renders and evaluates includeSelectorInFocusTrap. As a result, the selector isn’t accounted for in the focus trap, leading to focus getting lost:

500894863-d25031df-c550-4291-91d3-a4efdc3df717.mp4

Implementation details

This is the core of includeSelectorInFocusTrap functionality:

const focusTrapSelectors = useMemo(() => {
let selectors: string[] = [];
if (includeSelectorInFocusTrap) {
selectors = Array.isArray(includeSelectorInFocusTrap)
? includeSelectorInFocusTrap
: [includeSelectorInFocusTrap];
}
if (includeFixedHeadersInFocusTrap) {
selectors.push('.euiHeader[data-fixed-header]');
}
return selectors;
}, [includeSelectorInFocusTrap, includeFixedHeadersInFocusTrap]);
useEffect(() => {
if (focusTrapSelectors.length > 0) {
const shardsEls = focusTrapSelectors.flatMap((selector) =>
Array.from(document.querySelectorAll<HTMLElement>(selector))
);
setFocusTrapShards(Array.from(shardsEls));
// Flyouts that are toggled from shards do not have working
// focus trap autoFocus, so we need to focus the flyout wrapper ourselves
shardsEls.forEach((shard) => {
if (shard.contains(flyoutToggle.current)) {
resizeRef?.focus();
}
});
} else {
// Clear existing shards if necessary, e.g. switching to `false`
setFocusTrapShards((shards) => (shards.length ? [] : shards));
}
}, [focusTrapSelectors, resizeRef]);

The update reuses the same logic, passing it as a callback to the PubSub subscribe function. This lets the flyout detect when a publisher (e.g. EuiPopover) prompts a re-query of elements with includeSelectorInFocusTrap.

PubSub assures clear separation between EuiPopover and EuiFlyout without linking them in any way together.

Alternative approaches

  1. onKeyDown:
    Causes a race condition. Key events fire before the popover renders, making focus updates asynchronous and unreliable (in Storybook it required a double Enter, in Kibana it lost focus). It could be made better by delaying the re-queries by popover transition but that is a fragile patch.

  2. MutationObserver:
    Detects DOM changes but is costly and can hurt performance if not debounced. Can significantly impact the page load.

  3. React Context API:
    Works but adds unnecessary complexity and scope issues (requires global EuiProvider, otherwise is limited to a certain subtree).

Always publish

Always publishing from EuiPopover is the correct design here. A conditional prop would create a leaky abstraction, forcing developers to understand and manually connect the internal mechanics of EuiPopover and EuiFlyout.

The current approach keeps the components decoupled: the popover announces its state and the flyout listens. The performance cost of this is negligible and ensures the components work together automatically.

Impact to users

🟢 This should not cause regression to Flyout trap focus and keyboard navigation. It should improve keyboard navigation in side nav and flyout composition in Kibana. No API changes.

QA

Specific checklist

  • Reproduction story works as expected:
    • Popover not included in the focus trap loses focus
    • Popover included in the focus trap handles focus correctly

Popover keyboard navigation:

  • Enter to enter the popover on trigger focus
  • Esc to escape the popover on content focus

Before merge:

Testing in Kibana

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)
  • 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)

@weronikaolejniczak weronikaolejniczak self-assigned this Oct 16, 2025
@weronikaolejniczak weronikaolejniczak changed the title chore: add repro story fix(flyout): update focus trap shards in onKeyDown Oct 16, 2025
@weronikaolejniczak weronikaolejniczak force-pushed the fix/eui-flyout-trap-focus branch 3 times, most recently from f99a6ea to 9ffdff9 Compare October 16, 2025 15:22
@weronikaolejniczak weronikaolejniczak force-pushed the fix/eui-flyout-trap-focus branch from 9ffdff9 to db6685e Compare October 21, 2025 10:34
@weronikaolejniczak weronikaolejniczak force-pushed the fix/eui-flyout-trap-focus branch 2 times, most recently from 4d6940a to 97883f6 Compare October 31, 2025 12:17
@weronikaolejniczak weronikaolejniczak changed the title fix(flyout): update focus trap shards in onKeyDown fix(flyout): update focus trap shards through a PubSub Oct 31, 2025
@weronikaolejniczak weronikaolejniczak force-pushed the fix/eui-flyout-trap-focus branch 2 times, most recently from 695e5b1 to 6d3c47c Compare October 31, 2025 17:31
@weronikaolejniczak weronikaolejniczak marked this pull request as ready for review October 31, 2025 17:50
@weronikaolejniczak weronikaolejniczak requested a review from a team as a code owner October 31, 2025 17:50
@acstll acstll self-requested a review November 3, 2025 09:24
@weronikaolejniczak weronikaolejniczak changed the title fix(flyout): update focus trap shards through a PubSub feat(eui): add a focus trap pubsub service Nov 3, 2025
Copy link
Contributor Author

@weronikaolejniczak weronikaolejniczak Nov 3, 2025

Choose a reason for hiding this comment

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

WILL BE REVERTED

sorry for screaming

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.

I went through the QA steps provided and it's working as expected. The changes look good and the implementation is neat and clean (agree it's probably the best compared to the other possible approaches). Left a couple of comments.

We agreed with @weronikaolejniczak that it'll make sense to test this with the latest Flyout System changes as well, and that @tkajtoch should also take a look as well 🙂

Comment on lines 466 to 472
/**
* Finds the shards to include in the focus trap by querying by `focusTrapSelectors`.
*
* @param shouldAutoFocus Whether to auto-focus the flyout wrapper when the focus trap is activated.
* This is necessary because when a flyout is toggled from within a shard, the focus trap's `autoFocus`
* feature doesn't work. This logic manually focuses the flyout as a workaround.
*/
Copy link
Contributor

Choose a reason for hiding this comment

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

JSDoc FTW, thanks for adding this 💚

@tkajtoch tkajtoch self-requested a review November 4, 2025 12:33
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.

Thanks again for taking the time to address my comments @weronikaolejniczak

I'm approving knowing that we agree

  • @tkajtoch will also do a review
  • it will get tested in Kibana (with a test PR like elastic/kibana#239500 and CI green) after the current work for integrating the flyout system is stable

@weronikaolejniczak weronikaolejniczak force-pushed the fix/eui-flyout-trap-focus branch from 077d68f to 228bdda Compare November 5, 2025 12:37
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.

I like what I see in this PR very much. The solution seems thought out and doesn't open us to any new risks.

My comments are just comments and I don't expect you to change anything. LGTM 🚢

@@ -0,0 +1,73 @@
/*
Copy link
Member

Choose a reason for hiding this comment

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

[Not a change request] Semantically, this implements the observer pattern and not the pub-sub pattern, but the differences are minimal. It doesn't change the fact that this solution works here.

Copy link
Contributor Author

@weronikaolejniczak weronikaolejniczak Nov 7, 2025

Choose a reason for hiding this comment

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

I would say this is a hybrid approach, technically it's closer to Observer but conceptually it's closer to Pub/Sub. Why?

  • publish() does not know who the listeners are, it just broadcasts,
  • focusTrapPubSub acts as a mediator (the "message broker"), components call publish and subscribe on it,
  • Flyout and Popover communicate without references to one another,
  • the publisher doesn’t maintain observers tied to its own instance, it uses a shared event channel.

In the Observer pattern, the "subject" holds the list of observers. Here, no object owns the list, the listeners Set is a global event bus. This means multiple independent parts of the app can publish and subscribe. For now it's only Flyout being the subscriber and Popover the publisher but we could loop in other components as needed. Isn't that a Pub/Sub?

I'm genuinely curious, please let me know what was your thought process 😄

EDIT: One more thing that came to mind, I always thought of Observer as a tightly-coupling pattern while Pub/Sub as a loosely-coupling pattern, which is why Pub/Sub is great to use in a micro-frontend architecture for cross-module behaviors 👍🏻

EDIT 2: I guess what differs it from a true Pub/Sub is the "topics" (here we don't need them), and external message broker. Also the focusTrapPubSub is an in-memory singleton that synchronously loops through listeners, like an Observer subject. This is so nuanced, I don't think it's wrong to call it either Pub/Sub or Observer but the intention for this skews more for Pub/Sub 😅

* This is necessary because when a flyout is toggled from within a shard, the focus trap's `autoFocus`
* feature doesn't work. This logic manually focuses the flyout as a workaround.
*/
const findShards = useCallback(
Copy link
Member

Choose a reason for hiding this comment

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

Just a thought: Even since we can't do anything with react-focus-on's shards property that accepts type Array<React.RefObject<any> | HTMLElement>, it would still be possible to make it dynamic based on the usage. The library only accesses the data on two events - onMouseDown and the internal onNodeActivation. That means shards is only read then, which makes it a potential good candidate for a Proxy array that would work similarly to HTMLCollection but using querySelectorAll. Whenever the array would be read, it would read a dynamic value based on the output of document.querySelectorAll at the time of read.

I'm not saying this would be a better solution. I'm just mentioning it as a way to bend the rules :D

The best overall solution would likely be to open a feature request and allow shards to be a function or something more dynamic in general for these use cases.

Copy link
Contributor Author

@weronikaolejniczak weronikaolejniczak Nov 7, 2025

Choose a reason for hiding this comment

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

I love the idea of a Proxy array, it's very clever! 🧠 And removes the need for a subscription system.

I quickly whipped it up in a7faab2 and tested with the story:

Kapture.2025-11-07.at.12.03.24.mp4

We can always drop the commit in case we feel this is too risky (e.g. potential performance overhead due to frequent queries or the reliance of how react-focus-on handles shards array). I feel this would have to be re-tested thoroughly because it does affect other parts of the flyout code.

Lmk what you think, personally I'd revert to the pub/sub for potentially better performance and no compatibility risk but Proxy is a more elegant solution with less component coupling and less code to maintain.

Copy link
Member

Choose a reason for hiding this comment

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

Huge props for actually testing this and comparing both solutions! My primary intention was to just mention it and not push you in either direction. Your solution works perfectly fine and thanks to its simplicity I feel confident we can merge it and be able to enhance it if we ever need to in the future. The proxy solution might be useful someday, somewhere else 👍🏻

Copy link
Contributor Author

Choose a reason for hiding this comment

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

For prosperity, the diff would be sth like:

const focusTrapSelectors = useMemo(() => {
  let selectors: string[] = [];
  if (includeSelectorInFocusTrap) {
    selectors = Array.isArray(includeSelectorInFocusTrap)
      ? includeSelectorInFocusTrap
      : [includeSelectorInFocusTrap];
  }
  if (includeFixedHeadersInFocusTrap) {
    selectors.push('.euiHeader[data-fixed-header]');
  }
  return selectors;
}, [includeSelectorInFocusTrap, includeFixedHeadersInFocusTrap]);

const dynamicShards = useMemo(() => {
  const userShards = _focusTrapProps?.shards || [];

  if (focusTrapSelectors.length === 0) {
    return userShards;
  }

  const getDynamicNodes = () =>
    focusTrapSelectors.flatMap((selector) =>
      Array.from(document.querySelectorAll<HTMLElement>(selector))
    );

  return new Proxy(userShards, {
    get(target, prop) {
      const allNodes = [
        ...target, // consumer-provided shards
        ...getDynamicNodes(),
      ];
      const value = Reflect.get(allNodes, prop);

      if (typeof value === 'function') {
        return value.bind(allNodes);
      }

      return value;
    },
  });
}, [_focusTrapProps?.shards, focusTrapSelectors]);

const focusTrapProps: EuiFlyoutProps['focusTrapProps'] = useMemo(
  () => ({
    ..._focusTrapProps,
    shards: dynamicShards,
  }),
  [_focusTrapProps, dynamicShards]
);

Copy link
Contributor

Choose a reason for hiding this comment

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

it was amazing watching this work in a7faab2 💪

I must say it's the first time I see Proxy being practically useful (besides the typical reactivity implementations in UI libraries) 💚

@weronikaolejniczak weronikaolejniczak force-pushed the fix/eui-flyout-trap-focus branch from a7faab2 to 3e08a15 Compare November 7, 2025 13:58
@weronikaolejniczak weronikaolejniczak force-pushed the fix/eui-flyout-trap-focus branch from 3e08a15 to eed4fe4 Compare November 7, 2025 13:59
@elasticmachine
Copy link
Collaborator

💚 Build Succeeded

History

cc @weronikaolejniczak

@elasticmachine
Copy link
Collaborator

💚 Build Succeeded

History

cc @weronikaolejniczak

@weronikaolejniczak weronikaolejniczak merged commit 15f3d0a into elastic:main Nov 7, 2025
7 checks passed
acstll added a commit to elastic/kibana that referenced this pull request Nov 20, 2025
- `@elastic/eui`: `v109.0.0` ⏩ `v109.1.0`
- `@elastic/eslint-plugin-eui`: `v2.5.0` ⏩ `v2.6.0`

---

## Changes

- Updated i18n EUI mapping 6cc95b0
- Updated test in Unified Search
668948f

## Package updates

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

- Added `--euiBottomBarOffset` CSS variable to `EuiBottomBar` for
positioning other fixed elements relative to the bottom bar's height
([#9211](elastic/eui#9211))
- Updated `boxesVertical` icon and restored `checkInCircleFilled`,
`errorFilled`, and `warningFilled` icons.
([#9194](elastic/eui#9194))
- Updated `EuiSuperDatePicker` with new time zone information, opt-in
via `timeZoneDisplayProps`.
([#9191](elastic/eui#9191))
- Updated the position of `EuiModal` by removing bottom padding in
`EuiOverlayMask` ([#9190](elastic/eui#9190))
- Added `EuiPopover` and `EuiToolTip`'s `repositionOnScroll` to
`componentDefaults` ([#9152](elastic/eui#9152))
- Updated `EuiSuperDatePicker` with new time window buttons for time
shifting and zoom out, opt-in via `showTimeWindowButtons` boolean prop.
([#9151](elastic/eui#9151))
- Added beta prop `hasAriaDisabled` to all base button components:
`EuiButton`, `EuiButtonEmpty`, `EuiButtonIcon`, `EuibuttonGroup`,
`EuiFilterButton` ([#9201](elastic/eui#9201))
- Added `euiDisabledSelector` variable that combines CSS selectors
`:disabled` and `[aria-disabled="true"]`
([#9201](elastic/eui#9201))
- Added custom test matchers that check for both `disabled` and
`aria-disabled` attributes:
([#9201](elastic/eui#9201))
  - React testing Library: `.toBeEuiDisabled()`
  - Enzyme: `.toHaveEuiDisabledProp()`
  - Cypress: `should('be.euiDisabled)`

**Bug fixes**

- Fixed unexpected duplicate columns in `EuiDataGrid` crashing the
column sorting by removing duplicate columns entirely
([#9209](elastic/eui#9209))
- Fixed a visual bug in `EuiTable` where long table row content would be
cut off on mobile screens
([#9206](elastic/eui#9206))
- Fixed virtualized `EuiCodeBlock` rendering blank lines when content
updates if scrolled. ([#9196](elastic/eui#9196))
- Fixed `EuiButtonGroup` button sizing to ensure square buttons when
used with `isIconOnly=true`
([#9170](elastic/eui#9170))

**Accessibility**

- Fixed an issue where portalled components like `EuiPopover` were not
included in `EuiFlyout`'s focus trap through
`includeSelectorInFocusTrap`, making them inaccessible to keyboard users
([#9103](elastic/eui#9103))

### `@elastic/eslint-plugin-eui`
[`v2.6.0`](https://github.com/elastic/eui/blob/main/packages/eslint-plugin/changelogs/CHANGELOG_2025.md#v260)

- Added new `require-table-caption` rule.
([#9168](elastic/eui#9168))

---------

Co-authored-by: Elastic Machine <[email protected]>
andrimal pushed a commit to andrimal/kibana that referenced this pull request Nov 20, 2025
- `@elastic/eui`: `v109.0.0` ⏩ `v109.1.0`
- `@elastic/eslint-plugin-eui`: `v2.5.0` ⏩ `v2.6.0`

---

## Changes

- Updated i18n EUI mapping 6cc95b0
- Updated test in Unified Search
668948f

## Package updates

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

- Added `--euiBottomBarOffset` CSS variable to `EuiBottomBar` for
positioning other fixed elements relative to the bottom bar's height
([elastic#9211](elastic/eui#9211))
- Updated `boxesVertical` icon and restored `checkInCircleFilled`,
`errorFilled`, and `warningFilled` icons.
([elastic#9194](elastic/eui#9194))
- Updated `EuiSuperDatePicker` with new time zone information, opt-in
via `timeZoneDisplayProps`.
([elastic#9191](elastic/eui#9191))
- Updated the position of `EuiModal` by removing bottom padding in
`EuiOverlayMask` ([elastic#9190](elastic/eui#9190))
- Added `EuiPopover` and `EuiToolTip`'s `repositionOnScroll` to
`componentDefaults` ([elastic#9152](elastic/eui#9152))
- Updated `EuiSuperDatePicker` with new time window buttons for time
shifting and zoom out, opt-in via `showTimeWindowButtons` boolean prop.
([elastic#9151](elastic/eui#9151))
- Added beta prop `hasAriaDisabled` to all base button components:
`EuiButton`, `EuiButtonEmpty`, `EuiButtonIcon`, `EuibuttonGroup`,
`EuiFilterButton` ([elastic#9201](elastic/eui#9201))
- Added `euiDisabledSelector` variable that combines CSS selectors
`:disabled` and `[aria-disabled="true"]`
([elastic#9201](elastic/eui#9201))
- Added custom test matchers that check for both `disabled` and
`aria-disabled` attributes:
([elastic#9201](elastic/eui#9201))
  - React testing Library: `.toBeEuiDisabled()`
  - Enzyme: `.toHaveEuiDisabledProp()`
  - Cypress: `should('be.euiDisabled)`

**Bug fixes**

- Fixed unexpected duplicate columns in `EuiDataGrid` crashing the
column sorting by removing duplicate columns entirely
([elastic#9209](elastic/eui#9209))
- Fixed a visual bug in `EuiTable` where long table row content would be
cut off on mobile screens
([elastic#9206](elastic/eui#9206))
- Fixed virtualized `EuiCodeBlock` rendering blank lines when content
updates if scrolled. ([elastic#9196](elastic/eui#9196))
- Fixed `EuiButtonGroup` button sizing to ensure square buttons when
used with `isIconOnly=true`
([elastic#9170](elastic/eui#9170))

**Accessibility**

- Fixed an issue where portalled components like `EuiPopover` were not
included in `EuiFlyout`'s focus trap through
`includeSelectorInFocusTrap`, making them inaccessible to keyboard users
([elastic#9103](elastic/eui#9103))

### `@elastic/eslint-plugin-eui`
[`v2.6.0`](https://github.com/elastic/eui/blob/main/packages/eslint-plugin/changelogs/CHANGELOG_2025.md#v260)

- Added new `require-table-caption` rule.
([elastic#9168](elastic/eui#9168))

---------

Co-authored-by: Elastic Machine <[email protected]>
weronikaolejniczak added a commit to elastic/kibana that referenced this pull request Nov 21, 2025
…ems not interactive (#243685)

## Summary

There is a meaningful fix already on:
#243612

It's going into 9.3 and cannot be backported because it relies on latest
EUI updates
([v109.1.0](https://github.com/elastic/eui/releases/tag/v109.1.0)),
specifically:

> Fixed an issue where portalled components like EuiPopover were not
included in EuiFlyout's focus trap through includeSelectorInFocusTrap,
making them inaccessible to keyboard users
(elastic/eui#9103)

## QA

### Flyouts


https://github.com/user-attachments/assets/3957c82e-c5ed-4113-bd3d-5a8a3ffa5bd6

### Security PageOverlay


https://github.com/user-attachments/assets/9a491ba0-51b3-44d6-8d39-63aea538f2e6

### Keyboard navigation


https://github.com/user-attachments/assets/f1d8677c-5825-4ace-aa13-3b17b6b8b4e5
eokoneyo pushed a commit to eokoneyo/kibana that referenced this pull request Dec 2, 2025
- `@elastic/eui`: `v109.0.0` ⏩ `v109.1.0`
- `@elastic/eslint-plugin-eui`: `v2.5.0` ⏩ `v2.6.0`

---

## Changes

- Updated i18n EUI mapping 6cc95b0
- Updated test in Unified Search
668948f

## Package updates

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

- Added `--euiBottomBarOffset` CSS variable to `EuiBottomBar` for
positioning other fixed elements relative to the bottom bar's height
([elastic#9211](elastic/eui#9211))
- Updated `boxesVertical` icon and restored `checkInCircleFilled`,
`errorFilled`, and `warningFilled` icons.
([elastic#9194](elastic/eui#9194))
- Updated `EuiSuperDatePicker` with new time zone information, opt-in
via `timeZoneDisplayProps`.
([elastic#9191](elastic/eui#9191))
- Updated the position of `EuiModal` by removing bottom padding in
`EuiOverlayMask` ([elastic#9190](elastic/eui#9190))
- Added `EuiPopover` and `EuiToolTip`'s `repositionOnScroll` to
`componentDefaults` ([elastic#9152](elastic/eui#9152))
- Updated `EuiSuperDatePicker` with new time window buttons for time
shifting and zoom out, opt-in via `showTimeWindowButtons` boolean prop.
([elastic#9151](elastic/eui#9151))
- Added beta prop `hasAriaDisabled` to all base button components:
`EuiButton`, `EuiButtonEmpty`, `EuiButtonIcon`, `EuibuttonGroup`,
`EuiFilterButton` ([elastic#9201](elastic/eui#9201))
- Added `euiDisabledSelector` variable that combines CSS selectors
`:disabled` and `[aria-disabled="true"]`
([elastic#9201](elastic/eui#9201))
- Added custom test matchers that check for both `disabled` and
`aria-disabled` attributes:
([elastic#9201](elastic/eui#9201))
  - React testing Library: `.toBeEuiDisabled()`
  - Enzyme: `.toHaveEuiDisabledProp()`
  - Cypress: `should('be.euiDisabled)`

**Bug fixes**

- Fixed unexpected duplicate columns in `EuiDataGrid` crashing the
column sorting by removing duplicate columns entirely
([elastic#9209](elastic/eui#9209))
- Fixed a visual bug in `EuiTable` where long table row content would be
cut off on mobile screens
([elastic#9206](elastic/eui#9206))
- Fixed virtualized `EuiCodeBlock` rendering blank lines when content
updates if scrolled. ([elastic#9196](elastic/eui#9196))
- Fixed `EuiButtonGroup` button sizing to ensure square buttons when
used with `isIconOnly=true`
([elastic#9170](elastic/eui#9170))

**Accessibility**

- Fixed an issue where portalled components like `EuiPopover` were not
included in `EuiFlyout`'s focus trap through
`includeSelectorInFocusTrap`, making them inaccessible to keyboard users
([elastic#9103](elastic/eui#9103))

### `@elastic/eslint-plugin-eui`
[`v2.6.0`](https://github.com/elastic/eui/blob/main/packages/eslint-plugin/changelogs/CHANGELOG_2025.md#v260)

- Added new `require-table-caption` rule.
([elastic#9168](elastic/eui#9168))

---------

Co-authored-by: Elastic Machine <[email protected]>
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.

[EuiFlyout] Make flyout update focus trap shards

4 participants