Skip to content

[Flyout System] Support width offset using --euiFlyoutOffsetInlineEnd#9344

Closed
tsullivan wants to merge 14 commits intoelastic:mainfrom
tsullivan:flyout-system/transform-for-child-flyouts
Closed

[Flyout System] Support width offset using --euiFlyoutOffsetInlineEnd#9344
tsullivan wants to merge 14 commits intoelastic:mainfrom
tsullivan:flyout-system/transform-for-child-flyouts

Conversation

@tsullivan
Copy link
Copy Markdown
Member

Summary

  1. Main flyout positioning (flyout.styles.ts)

    • Base positioning: right: var(--euiFlyoutOffsetInlineEnd, 0)
    • Update all percentage-based width calculations (s=25%, m=50%, l=75%, fill=90%) to use calc(Xvw - X * var(--euiFlyoutOffsetInlineEnd, 0px))
    • Dynamic fill width: calc((90vw - 0.9 * var(--euiFlyoutOffsetInlineEnd, 0px)) - [sibling-width]px)
    • Max-width override: calc(90vw - 0.9 * var(--euiFlyoutOffsetInlineEnd, 0px))
  2. Child flyout positioning (flyout_child.tsx)

    • Position: right: calc([parent-width]px + var(--euiFlyoutOffsetInlineEnd, 0px))
  3. Layout mode logic (layout_mode.ts)

    • Use useEuiThemeCSSVariables().globalCSSVariables to read offset value
    • Calculate effectiveViewportWidth = windowWidth - flyoutOffset
    • Use effectiveViewportWidth for both:
      • Layout mode threshold comparisons (side-by-side ↔ stacked)
      • getWidthFromSize() calculations to match CSS behavior
    • Will not use hysteresis (flicker prevention) as testing shows unacceptably large gaps when combined with offset
  4. Storybook controls (flyout_manager.stories.tsx, flyout_sessions.stories.tsx)

    • Add flyoutOffset control (defaults to 0)
    • Use useEuiThemeCSSVariables().setGlobalCSSVariables() to set --euiFlyoutOffsetInlineEnd
    • Apply to all flyout manager stories (single-session, multi-session, multi-root)
  5. Consistent application

    • Ensure compatibility with all flyout types: overlay, push
    • Ensure compatibility with all flyout sizes: s, m, l, fill, custom pixel values
    • Resizable flyouts will maintain their existing behavior (width is user-controlled, static px-based width)
  6. Documentation

    • Add CSS API section to packages/eui/src/components/flyout/README.md (developer docs)
    • Add CSS Variables section to packages/website/docs/components/containers/flyout/index.mdx (public docs)
    • Document usage with useEuiThemeCSSVariables().setGlobalCSSVariables()

Why are we making this change?

Screenshots #

Impact to users

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)

Problem Analysis:
The layout mode was not transitioning from stacked to side-by-side when
viewport increased. Root cause was a circular dependency in the width
calculation logic:

1. Measured widths (parentWidth, childWidth) were used first for layout
   decisions
2. These measured widths come from actual DOM rendering
3. In stacked mode, flyouts render at different widths than side-by-side
4. Using those stacked-mode widths to decide if we should switch modes
   kept the layout stuck in stacked mode

Solution:
Prioritize calculated widths from size configuration over measured widths:
- Calculate widths using getWidthFromSize(size, windowWidth) first
- These are deterministic and independent of current layout mode
- Only fall back to measured widths if size is unavailable
- Use windowWidth (not effectiveViewportWidth) to match CSS vw units
- Use effectiveViewportWidth only for fit percentage calculation

Hysteresis Decision:
Initially considered reintroducing hysteresis (85%/95% thresholds) to
prevent flickering, but with 300px sidebar offset this creates a 1125px
gap between transitions (unacceptably large). With single 90% threshold,
the gap is minimal (~20px) in both scenarios, providing responsive and
predictable behavior.

Testing:
- Without offset: transitions at 800-820px (20px gap)
- With 300px offset: transitions at 1780-1800px (20px gap)
- Layout correctly switches in both directions
@elasticmachine
Copy link
Copy Markdown
Collaborator

💚 Build Succeeded

@elasticmachine
Copy link
Copy Markdown
Collaborator

💔 Build Failed

Failed CI Steps

@tsullivan
Copy link
Copy Markdown
Member Author

Closing this since a better proposal has come up

@tsullivan tsullivan closed this Feb 5, 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.

2 participants