Skip to content

[EuiAccordion] Migrate from class to function component#9558

Open
antonbc wants to merge 3 commits intoelastic:mainfrom
antonbc:refactor/accordion-function-component
Open

[EuiAccordion] Migrate from class to function component#9558
antonbc wants to merge 3 commits intoelastic:mainfrom
antonbc:refactor/accordion-function-component

Conversation

@antonbc
Copy link
Copy Markdown

@antonbc antonbc commented Apr 4, 2026

…d useEuiTheme

Summary

API Changes

No API changes.

component / parent prop / child change description

Screenshots

No visual changes

Before After
{Before image} {After image}

Impact Assessment

Note: Most PRs should be tested in Kibana to help gauge their Impact before merging.

  • 🔴 Breaking changes
  • 💅 Visual changes
  • 🧪 Test impact — None. All 39 existing tests pass, 21 snapshots match.
  • 🔧 Hard to integrate

Impact level: 🟢 None / 🟢 Low / 🟡 Moderate / 🔴 High

Release Readiness

  • Documentation:
  • Figma:
  • Migration guide:
  • Adoption plan

QA instructions for reviewer

Checklist before marking Ready for Review

Reviewer checklist

  • Convert to function component with useState
  • Replace withEuiTheme HOC with useEuiTheme hook if applicable
  • Maintain controlled/uncontrolled open state behavior
  • All existing tests pass

@antonbc antonbc requested a review from a team as a code owner April 4, 2026 07:30
Copilot AI review requested due to automatic review settings April 4, 2026 07:30
@cla-checker-service
Copy link
Copy Markdown

cla-checker-service bot commented Apr 4, 2026

💚 CLA has been signed

@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 4, 2026

👋 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 Apr 4, 2026
@antonbc antonbc closed this Apr 4, 2026
@antonbc antonbc reopened this Apr 4, 2026
@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 4, 2026

👋 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?

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Migrates EuiAccordion from a class component wrapped in withEuiTheme to a function component that uses hooks (useEuiTheme, useGeneratedHtmlId) while aiming to keep behavior and public API the same.

Changes:

  • Replaced class state/handlers with useState and an internal toggle handler.
  • Replaced withEuiTheme + WithEuiThemeProps usage with useEuiTheme.
  • Replaced htmlIdGenerator() instance property with useGeneratedHtmlId().

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

Comment on lines +152 to +156
setIsOpenState((prevIsOpen) => {
const nextState = !prevIsOpen;
onToggle?.(nextState);
return nextState;
});
Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

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

onToggle is invoked inside the setIsOpenState functional updater. React may call state updater functions more than once (e.g., StrictMode/dev, interrupted renders), which can lead to onToggle firing multiple times for a single user interaction. Consider computing nextState in the click handler using the current isOpenState, calling setIsOpenState(nextState), and then calling onToggle(nextState) outside the updater (or triggering the callback from an effect that only runs for user-initiated toggles).

Suggested change
setIsOpenState((prevIsOpen) => {
const nextState = !prevIsOpen;
onToggle?.(nextState);
return nextState;
});
const nextState = !isOpenState;
setIsOpenState(nextState);
onToggle?.(nextState);

Copilot uses AI. Check for mistakes.
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.

Let's please address this.

Comment on lines +163 to +170
const euiTheme = useEuiTheme();
const classes = classNames(
'euiAccordion',
{ 'euiAccordion-isOpen': isOpen },
className
);

const styles = euiAccordionStyles(euiTheme);
Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

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

useEuiTheme() returns a theme object (with euiTheme, colorMode, etc.), but the local variable is named euiTheme, which reads like it contains only the euiTheme property. Renaming this variable to theme (or destructuring { euiTheme } and adjusting the style call accordingly) would avoid confusion and reduce the chance of misusing the hook return value later.

Suggested change
const euiTheme = useEuiTheme();
const classes = classNames(
'euiAccordion',
{ 'euiAccordion-isOpen': isOpen },
className
);
const styles = euiAccordionStyles(euiTheme);
const theme = useEuiTheme();
const classes = classNames(
'euiAccordion',
{ 'euiAccordion-isOpen': isOpen },
className
);
const styles = euiAccordionStyles(theme);

Copilot uses AI. Check for mistakes.
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.

We actually use euiThemeContext:

const euiThemeContext = useEuiTheme();
const styles = euiAccordionStyles(euiThemeContext);

@weronikaolejniczak weronikaolejniczak added the skip-changelog Use on PRs to skip changelog requirement (Don't delete - used for automation) label Apr 7, 2026
Comment thread packages/eui/changelogs/upcoming/9558.md Outdated
className
);

const styles = euiAccordionStyles(euiTheme);
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.

This was not part of the task but we could use useEuiMemoizedStyles

@elasticmachine
Copy link
Copy Markdown
Collaborator

💚 Build Succeeded

@elasticmachine
Copy link
Copy Markdown
Collaborator

💚 Build Succeeded


onToggle = () => {
const { forceState } = this.props;
export const EuiAccordionClass: FunctionComponent<EuiAccordionProps> = ({
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:

We should export it directly as EuiAccordion, not EuiAccordionClass because that's no longer true.

Suggested change
export const EuiAccordionClass: FunctionComponent<EuiAccordionProps> = ({
export const EuiAccordion: FunctionComponent<EuiAccordionProps> = ({

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) skip-changelog Use on PRs to skip changelog requirement (Don't delete - used for automation)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants