Skip to content

[Flyout System] Add flyout menu display modes#9426

Merged
angeles-mb merged 8 commits intoelastic:mainfrom
angeles-mb:2670-hide-header-when-only-close-button-present
Mar 13, 2026
Merged

[Flyout System] Add flyout menu display modes#9426
angeles-mb merged 8 commits intoelastic:mainfrom
angeles-mb:2670-hide-header-when-only-close-button-present

Conversation

@angeles-mb
Copy link
Copy Markdown
Contributor

@angeles-mb angeles-mb commented Mar 5, 2026

Summary

This PR:

  • Adds a new flyoutMenuDisplayMode prop to EuiFlyout to control when the flyout menu bar is rendered:
    • 'auto' (default): Menu only renders when it has meaningful content (back button, history, visible title, or custom actions).
    • 'always': Menu always renders, this might result in a menu with nothing else than a close button.
  • Updated flyout manager playground stories to be able to test this on Storybook. Relevant controls are: mainFlyoutMenuDisplayMode, childFlyoutMenuDisplayMode, showMainCustomActions and showChildCustomActions.
  • Moved logic related to the flyout menu to a custom hook.

Why are we making this change?

This change hides the menu when it only displays a close button and thus save some flyout space. Additionally, it gives consumers control over the menu bar visibility, allowing them to opt into 'always' mode.

Closes https://github.com/elastic/kibana-team/issues/2670.

Screenshots #

Before: main shows menu even if there is no meaningful content (no mode, menu always shown):
Screenshot 2026-03-06 at 15 55 56

After: main hides menu because there is no meaningful content ('auto' default):
Screenshot 2026-03-06 at 15 29 15

After: main shows menu because there is meaningful content (either 'auto' default or 'always' mode):
Screenshot 2026-03-06 at 15 29 39

After: main shows menu even if there is no meaningful content ('always' mode):
Screenshot 2026-03-06 at 15 29 58

Testing in kibana:

Before: main shows menu even if there is no meaningful content (no mode, menu always shown):
Screenshot 2026-03-06 at 16 07 24

Before: main shows menu and there is meaningful content (no mode, menu always shown):
Screenshot 2026-03-06 at 16 07 37

After: main hides menu because there is no meaningful content ('auto' default):
Screenshot 2026-03-06 at 15 52 52

After: main shows menu because there is meaningful content (either 'auto' default or 'always' mode):
Screenshot 2026-03-06 at 15 53 20

Testing checklist:

Storybook EuiFlyout > Flyout Manager > Playground:

  • Default story shows main (with actions) and child menu (with title + actions), custom actions defaults to true for both, display mode defaults to auto
  • Child: toggle showChildCustomActions to false, menu still renders (with title)
  • Child: toggle showChildCustomActions to false, toggle childFlyoutMenuDisplayMode to always menu still renders (with title)
  • Main: toggle showMainCustomActions to false, menu does not render, stand alone close button renders instead
  • Main: toggle showMainCustomActions to false, toggle mainFlyoutMenuDisplayMode to always menu renders with only a close button inside

Storybook EuiFlyout > EuiFlyout > Playground:

  • Default story shows flyout menu (with actions), custom actions defaults to true, display mode defaults to auto
  • Toggle showCustomActions to false, menu does not render, stand alone close button renders instead
  • Toggle showCustomActions to false, toggle flyoutMenuDisplayMode to always menu renders with only a close button inside

Kibana flyout examples:
If you want to test in kibana follow these instructions to test kibana against this branch. Test the System flyouts in the Flyout System Example (search for it on the global search bar)

  • Open Main Session J: main flyout doesn't show menu, single close button instead.
  • Open Session J child: child flyout shows menu with title.
  • Open another managed session: main flyout shows menu with back button and history dropdown.
  • Open its child: child flyout shows menu with title.

Impact to users

Flyout users will stop seeing an empty menu which only contains a close button when there is no meaningful content.

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 self-assigned this Mar 5, 2026
@angeles-mb angeles-mb marked this pull request as ready for review March 9, 2026 10:28
@angeles-mb angeles-mb requested a review from a team as a code owner March 9, 2026 10:28
@angeles-mb angeles-mb force-pushed the 2670-hide-header-when-only-close-button-present branch from 6e03cd9 to 5f55d2a Compare March 10, 2026 09:46
@mgadewoll mgadewoll self-requested a review March 10, 2026 10:47
@weronikaolejniczak weronikaolejniczak requested review from weronikaolejniczak and removed request for mgadewoll March 12, 2026 09:36
Copy link
Copy Markdown
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 only EUI Storybook. Thank you for the detailed testing checklist 🙏🏻 Code looks alright, everything works as expected. I only found a couple of nits and have 2 questions.

EDIT:

One more thing I noticed, I think there are a couple of test cases missing.

use_flyout_menu.test.ts:

describe('flyoutMenuHideTitle', () => {
  it('returns true when flyout is the main flyout in session', () => {});
  it('returns false when flyout is not the main flyout', () => {});
  it('returns true when explicit hideTitle is true', () => {});
  it('returns false when explicit hideTitle is false even for main flyout', () => {});
});

describe('shouldRenderMenu with display modes', () => {
  describe('always mode', () => {
    it('returns true even when menu has no content', () => {});
  });

  describe('auto mode', () => {
    it('returns true when menu has back button', () => {});
    it('returns true when menu has history items', () => {});
    it('returns true when menu has custom actions', () => {});
    it('returns true when menu has visible title', () => {});
    it('returns false when menu has no content', () => {});
    it('returns false when menu only has a hidden title', () => {});
  });
});

describe('ariaLabelledBy', () => {
  it('includes flyoutMenuId when menu is rendered', () => {});
  it('combines flyoutMenuId with existing ariaLabelledBy', () => {});
  it('excludes flyoutMenuId when auto mode hides the menu', () => {});
});

flyout.test.tsx:

describe('flyoutMenuDisplayMode', () => {
  describe('always mode', () => {
    it('renders menu even when menu has no content', () => {});
  });

  describe('auto mode', () => {
    it('renders menu when menu has content', () => {});
    it('renders close button when menu has no content', () => {});
    it('renders no close button when hideCloseButton is true and menu has no content', () => {});
  });

  describe('aria-labelledby', () => {
    it('includes menu titleId when menu is rendered', () => {});
    it('excludes menu titleId when auto mode hides the menu', () => {});
  });
});

Comment on lines +1091 to +1105
{shouldRenderMenu ? (
<EuiFlyoutMenu
{...flyoutMenuProps}
hideTitle={flyoutMenuHideTitle}
titleId={flyoutMenuId}
/>
) : (
!hideCloseButton && (
<EuiFlyoutCloseButton
{...closeButtonProps}
onClose={handleClose}
closeButtonPosition={closeButtonPosition}
side={side}
/>
)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

doubt:

What if the consumer uses auto mode (which it is by default) and hideCloseButton: true? There would be no close button at all. It's an unlikely case but could happen...

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I thought about this as well but documentation is clear, if using hideCloseButton, independently of the menu display mode, consumers must provide another close button somewhere in the flyout:

  /**
   * Hides the default close button. You must provide another close button somewhere within the flyout.
   * @default false
   */
  hideCloseButton?: boolean;

@angeles-mb angeles-mb force-pushed the 2670-hide-header-when-only-close-button-present branch from 5f55d2a to 3727d25 Compare March 13, 2026 09:37
@angeles-mb
Copy link
Copy Markdown
Contributor Author

Thanks for reviewing and testing @weronikaolejniczak 🙇‍♀️ I increased test coverage with the missing test cases you suggested and applied your other comments.

Copy link
Copy Markdown
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.

The latest updates LGTM! 🟢 I did a quick smoke-test in Storybook and it's still working as expected. Thank you, @angeles-mb! 🚢

@elasticmachine
Copy link
Copy Markdown
Collaborator

💚 Build Succeeded

History

cc @angeles-mb

@elasticmachine
Copy link
Copy Markdown
Collaborator

💚 Build Succeeded

History

cc @angeles-mb

@angeles-mb angeles-mb merged commit 5dadc1f into elastic:main Mar 13, 2026
5 checks passed
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.

4 participants