Skip to content

Fix EuiAccordion zero height under React Strict Mode - #9811

Open
cleydyr wants to merge 6 commits into
elastic:mainfrom
cleydyr:fix/accordion-strict-mode-9029
Open

Fix EuiAccordion zero height under React Strict Mode#9811
cleydyr wants to merge 6 commits into
elastic:mainfrom
cleydyr:fix/accordion-strict-mode-9029

Conversation

@cleydyr

@cleydyr cleydyr commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Summary

  • What: Fixed EuiAccordion rendering with zero height in React 18 Strict Mode, including when mounted inside EuiFlyout with initialIsOpen.
  • Why: Fixes #9029. Under Strict Mode, accordion content collapsed because contentHeight stayed 0 — most commonly seen with initialIsOpen and in flyouts.
  • How: Three coordinated changes:
    1. useObserver — Reconnect observers after Strict Mode effect cleanup (React 18 often disconnects without re-firing the ref callback). Clear observerRef on cleanup.
    2. EuiResizeObserver — Reset cached dimensions in beginObserve so the first callback after reconnect always fires onResize.
    3. EuiAccordionChildren — Omit inline block-size: 0 while open and awaiting the first measurement, allowing CSS height: auto to show content immediately.

Regression coverage added in accordion_strict_mode.test.tsx, use_observer.test.tsx, and resize_observer.test.tsx. Storybook stories added for standalone and flyout reproductions.

API Changes

component / parent prop / child change description
No public API changes

Screenshots

(from Storybook)

Captura de pantalla 2026-07-15 a las 18 06 21 Captura de pantalla 2026-07-15 a las 18 06 03

Impact Assessment

  • 🔴 Breaking changes — What will break? How many usages in Kibana/Cloud UI are impacted?
  • 💅 Visual changes — Open accordions no longer render style="block-size: 0;" before the first resize measurement. Snapshot tests updated accordingly. No intentional visual regression expected once content is measured.
  • 🧪 Test impact — 2 accordion snapshots updated (removed block-size: 0 on open). New unit/integration tests added. Full suite passes on React 17 and 18 (459 suites / 6461 tests).
  • 🔧 Hard to integrate — No consumer code changes required.

Impact level: 🟢 Low

Release Readiness

  • Documentation: No docs changes required (bug fix)
  • Figma: N/A
  • Migration guide: N/A
  • Adoption plan (new features): N/A

QA instructions for reviewer

  1. Run Storybook from packages/eui: yarn start
  2. Open Layout → EuiAccordion → Strict Mode In Flyout
    • Confirm gray accordion content is visible on load
    • Inspect .euiAccordion__childWrapper — should not have block-size: 0px while open
  3. Open Layout → EuiAccordion → Strict Mode Initial Open
    • Confirm content is visible immediately (not collapsed)
  4. Toggle accordion closed/open in both stories
    • Confirm open/close animation still works after first interaction
  5. Optional: verify a Kibana flyout with initialIsOpen accordions (see issue [Strict Mode] EuiAccordion doesn't display within EuiFlyout #9029 for known usages)

Checklist before marking Ready for Review

  • Filled out all sections above
  • QA: Tested light/dark modes, high contrast, mobile, Chrome/Safari/Edge/Firefox, keyboard-only, screen reader
  • QA: Tested in CodeSandbox and Kibana
  • QA: Tested docs changes
  • Tests: Added/updated Jest tests
  • Changelog: Added packages/eui/changelogs/upcoming/9029.md (rename to PR number after opening, if following yarn yo-changelog convention)
  • Breaking changes: N/A

Reviewer checklist

  • Approved Impact Assessment — Acceptable to merge given the consumer impact.
  • Approved Release Readiness — Docs, Figma, and migration info are sufficient to ship.

cleydyr and others added 5 commits July 15, 2026 18:11
…e compatibility

- updated EuiAccordionChildren to handle content height correctly
- change useObserver to reconnect observers correctly when remounting
- reset cached dimensions for accurate onResize callbacks
- improved tests for observer components to validate behavior under Strict Mode (I can remove it if it's not convenient for it to be there)
- added a new story for EuiAccordion demonstrating initial open state within Strict Mode (ditto, can remove it).
… EuiFlyout

- new test for EuiAccordion to validate its behavior under React Strict Mode when rendered inside an EuiFlyout.
- added a corresponding story to demonstrate the accordion's functionality in this context, addressing issue elastic#9029.
- enhanced the existing EuiAccordion stories to include examples of its use in Strict Mode (can remove it if needed).
Co-authored-by: Cursor <cursoragent@cursor.com>
@cleydyr
cleydyr requested a review from a team as a code owner July 15, 2026 16:24
@github-actions

Copy link
Copy Markdown

👋 Since this is a community submitted pull request, a Buildkite build has not been started automatically. Would an Elastic organization member please verify the contents of this pull request and kick off a build manually?

@github-actions github-actions Bot added the community contribution (Don't delete - used for automation) label Jul 15, 2026
@weronikaolejniczak

Copy link
Copy Markdown
Contributor

buildkite test this

@infra-vault-gh-plugin-prod

Copy link
Copy Markdown

💚 Build Succeeded

@infra-vault-gh-plugin-prod

infra-vault-gh-plugin-prod Bot commented Jul 21, 2026

Copy link
Copy Markdown

💔 Build Failed

Failed CI Steps

History

@weronikaolejniczak weronikaolejniczak left a comment

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.

Hey @cleydyr 👋🏻 Thanks for contributing to EUI, this helps us a lot 🙏🏻

I tested this in Storybook and it works perfectly 💖

I found a nit and 3 blocking issues. Other than that, we'd have to drop the commit that adds the baselines along with the stories (870563a).

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.

blocking:

We can add a small targeted unit test in the existing accordion.test.tsx file. We don't need a separate suite just for Strict Mode 😄

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.

blocking:

For testing the result it's fine but before I approve, we have to remove these stories. We don't need StrictMode specific ones.

Comment on lines +96 to +108
const heightInlineStyle = useMemo(() => {
if (!isOpen) {
return { blockSize: 0 };
}

// Avoid overriding CSS `height: auto` with `0` before the first resize
// measurement (e.g. `initialIsOpen` under React Strict Mode).
if (contentHeight === 0) {
return undefined;
}

return { blockSize: contentHeight };
}, [isOpen, contentHeight]);

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.

nit:

This is very opinionated but we could tighten this like so:

Suggested change
const heightInlineStyle = useMemo(() => {
if (!isOpen) {
return { blockSize: 0 };
}
// Avoid overriding CSS `height: auto` with `0` before the first resize
// measurement (e.g. `initialIsOpen` under React Strict Mode).
if (contentHeight === 0) {
return undefined;
}
return { blockSize: contentHeight };
}, [isOpen, contentHeight]);
const heightInlineStyle = useMemo(() => {
if (!isOpen) return { blockSize: 0 };
// Avoid overriding CSS `height: auto` with `0` before the first resize.
if (contentHeight === 0) return undefined;
return { blockSize: contentHeight };
}, [isOpen, contentHeight]);

instead of having 13 lines we have 6 and the code is equally meaningful.

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.

blocking:

The filename is supposed to be 9811.md, from the PR number.

Copilot AI left a comment

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.

Pull request overview

Fixes a React 18 Strict Mode regression where EuiAccordion content could render at zero height (notably when initialIsOpen inside EuiFlyout) by hardening observer lifecycle handling and avoiding premature block-size: 0 inline styles before first measurement.

Changes:

  • Reconnect observers in useObserver after Strict Mode effect cleanup and ensure observers can resume even when refs aren’t re-fired.
  • Ensure EuiResizeObserver emits onResize after reconnect by resetting cached dimensions on (re)observe.
  • Prevent open accordions from temporarily forcing block-size: 0 before the first resize measurement; add stories + regression tests and update snapshots/changelog.

Reviewed changes

Copilot reviewed 9 out of 11 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
packages/eui/src/components/observer/use_observer.ts Reconnects observers after Strict Mode cleanup; clears observer ref on cleanup.
packages/eui/src/components/observer/use_observer.test.tsx Adds Strict Mode reconnection regression test.
packages/eui/src/components/observer/resize_observer/resize_observer.tsx Resets cached size on observe so post-reconnect onResize fires.
packages/eui/src/components/observer/resize_observer/resize_observer.test.tsx Adds unit coverage asserting onResize fires again after reconnect.
packages/eui/src/components/accordion/accordion_children/accordion_children.tsx Avoids inline block-size: 0 while open and awaiting first measurement.
packages/eui/src/components/accordion/accordion.stories.tsx Adds Strict Mode reproduction stories (standalone + in flyout).
packages/eui/src/components/accordion/accordion_strict_mode.test.tsx Adds regression test for Strict Mode + flyout + initialIsOpen.
packages/eui/src/components/accordion/snapshots/accordion.test.tsx.snap Updates snapshots for removed block-size: 0 inline style when open.
packages/eui/changelogs/upcoming/9029.md Adds bugfix changelog entry for issue #9029.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +23 to +31
jest.mock('../observer/resize_observer/resize_observer.tsx', () => {
const { createResizeObserverMock } = jest.requireActual<
typeof import('../../test/internal')
>('../../test/internal');
resizeObserverMockRef.current = createResizeObserverMock();
global.ResizeObserver = resizeObserverMockRef.current.ResizeObserver;

return jest.requireActual('../observer/resize_observer/resize_observer.tsx');
});
Comment on lines +110 to +112
(process.env.REACT_VERSION === '18' ? it : it.skip)(
'reconnects the observer after StrictMode remounts without a ref change',
() => {
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

community contribution (Don't delete - used for automation)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Strict Mode] EuiAccordion doesn't display within EuiFlyout

5 participants