Skip to content

[Flyout System] Add main flyout to child focus trap#9397

Merged
angeles-mb merged 6 commits intoelastic:mainfrom
angeles-mb:9334-add-main-flyout-to-child-focus-trap
Mar 2, 2026
Merged

[Flyout System] Add main flyout to child focus trap#9397
angeles-mb merged 6 commits intoelastic:mainfrom
angeles-mb:9334-add-main-flyout-to-child-focus-trap

Conversation

@angeles-mb
Copy link
Contributor

@angeles-mb angeles-mb commented Feb 18, 2026

Summary

This PR:

  • Adds the parent flyout selector to the child focus trap to enable keyboard navigation between child and parent flyout. Parent is added only when both flyouts are side by side and not stacked
  • Defers aria-modal attribute to main flyout to avoid having inside one focus trap 2 elements with aria-modal
  • Adds cypress test to verify expected keyboard behavior between main and child flyout
  • Modifies SR announcements for overlay flyouts without a masked overlay to be coherent with aria semantics (parent and child behaving as a single modal unit)
  • Updates flyout's a11y docs

Why are we making this change?

Closes #9334

Mouse users can interact with the parent flyout while the child flyout is open. Before this change, keyboard users could only navigate inside the child flyout or close it. With this change, keyboard users will be able to achieve the same navigation as mouse users by navigating between flyouts.

You can read more about how we use Flyouts in Kibana to better understand why we are making this change here.

Screenshots #

Relevant use cases to test in Flyout Manager stories:

  • Keyboard navigation flows naturally between parent and child flyouts (either push or overlay type)
  • For stacked mode (narrow your screen to achieve this, side-by-side child transitions into stacked): main flyout is visually behind and not keyboard-navigable

VMWareFusion + Chrome + NVDA:

Before After
Screen.Recording.2026-02-27.at.11.41.01.mov
Screen.Recording.2026-02-27.at.11.33.57.mov

Kibana Chrome + VO:

Before After
Screen.Recording.2026-02-27.at.12.14.54.mov
Screen.Recording.2026-02-27.at.12.24.25.mov

If you want to test on Kibana:

  • Create a build of EUI with this branch
  • Run kibana with yarn start --run-examples
  • Test the System flyouts in the Flyout System Example (search for it on the global search bar)

If testing in Safari, notice that you will encounter keyboard navigation issues related to this a11y issue we currently have open: Skip to main content not working when there is opened flyout

Impact to users

A11y enhancement.

QA

Remove or strikethrough items that do not apply to your PR.

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)

@angeles-mb angeles-mb force-pushed the 9334-add-main-flyout-to-child-focus-trap branch from a7d8c6b to 71d6d6b Compare February 18, 2026 12:01
@angeles-mb angeles-mb marked this pull request as ready for review February 18, 2026 13:51
@angeles-mb angeles-mb requested a review from a team as a code owner February 18, 2026 13:51
@angeles-mb angeles-mb self-assigned this Feb 18, 2026
Copy link
Contributor

@weronikaolejniczak weronikaolejniczak left a comment

Choose a reason for hiding this comment

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

🟢 I tested in EUI Storybook and confirmed this is working as expected:

Before (prod) After
Kapture.2026-02-18.at.16.56.59.mp4
Kapture.2026-02-18.at.16.55.50.mp4

❌ But I also tested in Kibana. I validated it doesn't work before but it seems after using the EUI version from this PR the issue is not solved:

Before:

Kapture.2026-02-18.at.16.38.49.mp4

After:

Kapture.2026-02-18.at.16.49.19.mp4

My testing steps:

# in Kibana
yarn es
yarn start --run-examples
# validated it you cannot move with the keyboard from child to the parent flyout

# in EUI
gh pr checkout 9397
yarn workspace @elastic/eui build-pack
mv package.tgz ../kibana

# in Kibana
# updated in `package.json` to `@elastic/eui: "file:./package.tgz"`
yarn kbn bootstrap --no-validate

AFAIK this should work and we don't need to make any additional changes on Kibana side, right?

Additionally, it's not a blocking suggestion but the test could be even better if we validated the expected keyboard behavior 😄

@angeles-mb
Copy link
Contributor Author

I tested this on Kibana's side and this is what I'm seeing:

  • I'm able to navigate from one flyout to another with keyboard navigation
  • Keyboard navigation follows the flow of the flyout, that is, you have to go back with the keyboard to be able to move from the child flyout to the parent flyout

Would that be "acceptable" from an a11y point of view @weronikaolejniczak ?

Screen.Recording.2026-02-18.at.17.32.23.mov

@angeles-mb angeles-mb force-pushed the 9334-add-main-flyout-to-child-focus-trap branch from 71d6d6b to fe33f3f Compare February 26, 2026 14:57
@angeles-mb angeles-mb force-pushed the 9334-add-main-flyout-to-child-focus-trap branch from fe33f3f to 94879e2 Compare February 27, 2026 10:22
@weronikaolejniczak weronikaolejniczak self-requested a review March 2, 2026 09:17
Comment on lines +563 to +567
// Include parent in focus trap shards for side-by-side mode (unified navigation).
// In stacked mode, parent is hidden behind child so shouldn't be navigable.
if (isSideBySideChild) {
selectors.push(`[${PROPERTY_LEVEL}="${LEVEL_MAIN}"]`);
}
Copy link
Contributor

@weronikaolejniczak weronikaolejniczak Mar 2, 2026

Choose a reason for hiding this comment

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

question:

Logically, if the contrary is the truth (!isSideBySideChild), we should remove that selector from focus trap selectors?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't think that is necessary since the main flyout selector is only added conditionally and recalculated on every render. At first I had it added for every child flyout. Then I realized that if I did that, we would be able to navigate between child and parent flyouts which were stacked (we would confusingly navigate to a parent flyout which was not visible).

@weronikaolejniczak weronikaolejniczak self-requested a review March 2, 2026 09:57
Copy link
Contributor

@weronikaolejniczak weronikaolejniczak left a comment

Choose a reason for hiding this comment

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

This time I was only testing in Kibana with EUI built from this PR.

Everything works as I would expect it to. We can navigate between the child and main flyout (and other global page landmarks), all expected announcements are made, ARIA attributes are applied as per @alexwizp's concern.

From me it's 🟢 Thank you for your patience, for digging deeper and coming with a perfectly balanced solution, Angeles!

I'm not sure why JAWS doesn't announce everything as expected so I'd double-check the result with @alexwizp or @bhavyarm. But for me because NVDA and VO are working, I can tab through the flyouts and ARIA are applied correctly, it's okay.

✅ ARIA attributes

Side-by-side:

Image

The main flyout has role="dialog" and aria-modal.

Stacked:

Image

The child flyout has role="dialog" and aria-modal.

✅ Safari + VO

Kapture.2026-03-02.at.11.30.30.mp4

(Turn on sound 🔊)

✅ Edge + NVDA (Windows in Parallels VM)

Kapture.2026-03-02.at.11.57.17.mp4

(Turn on sound, be careful cause it's distorted 🔊)

⚠️ Edge + JAWS (Windows in Parallels VM)

Kapture.2026-03-02.at.12.04.38.mp4

Some announcements are missing in Firefox for the child flyout.

(Turn on sound, be careful cause it's distorted 🔊)

⚠️ Firefox + JAWS (Windows in Parallels VM)

Kapture.2026-03-02.at.12.01.34.mp4

Some announcements are missing in Firefox for the child flyout.

(Turn on sound, be careful cause it's distorted 🔊)

@angeles-mb
Copy link
Contributor Author

Thanks for the review and such thorough testing @weronikaolejniczak 🙌

@bhavyarm
Copy link
Contributor

bhavyarm commented Mar 2, 2026

@weronikaolejniczak Thanks so much for such thorough testing. Making a note about jaws.
@angeles-mb thanks for making every effort to make accessibility first class citizen! (bows)

@elasticmachine
Copy link
Collaborator

💚 Build Succeeded

History

cc @angeles-mb

@elasticmachine
Copy link
Collaborator

💚 Build Succeeded

History

cc @angeles-mb

@angeles-mb angeles-mb merged commit 7515df8 into elastic:main Mar 2, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2️⃣ [Flyouts] Focus trap can not be disabled for overlay flyouts

5 participants