Skip to content

Commit 981623a

Browse files
committed
fix(accordion): trying to prevent animation based on interaction rather than render
1 parent f84c484 commit 981623a

File tree

1 file changed

+43
-19
lines changed

1 file changed

+43
-19
lines changed

core/src/components/accordion/accordion.tsx

Lines changed: 43 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,14 @@ export class Accordion implements ComponentInterface {
4141
private accordionGroupEl?: HTMLIonAccordionGroupElement | null;
4242
private updateListener = (ev: CustomEvent<AccordionGroupChangeEventDetail>) => {
4343
const initialUpdate = ev.detail?.initial ?? false;
44+
/**
45+
* If this is not an initial update (meaning it's from a user interaction
46+
* or programmatic call after load), mark that we've had an interaction.
47+
* This enables animations for this and future updates.
48+
*/
49+
if (!initialUpdate) {
50+
this.hasInteracted = true;
51+
}
4452
this.updateState(initialUpdate);
4553
};
4654
private contentEl: HTMLDivElement | undefined;
@@ -55,12 +63,18 @@ export class Accordion implements ComponentInterface {
5563
@State() isNext = false;
5664
@State() isPrevious = false;
5765
/**
58-
* Tracks whether the component has completed its initial render.
59-
* Animations are disabled until after the first render completes.
60-
* This prevents the accordion from animating when it starts
61-
* expanded or collapsed on initial load.
66+
* Tracks whether a user-initiated interaction has occurred.
67+
* Animations are disabled until the first interaction happens.
68+
* This prevents the accordion from animating when it's programmatically
69+
* set to an expanded or collapsed state on initial load.
6270
*/
63-
@State() hasRendered = false;
71+
@State() hasInteracted = false;
72+
73+
/**
74+
* Tracks if this accordion has ever been expanded.
75+
* Used to prevent the first expansion from animating.
76+
*/
77+
private hasEverBeenExpanded = false;
6478

6579
/**
6680
* The value of the accordion. Defaults to an autogenerated
@@ -130,17 +144,6 @@ export class Accordion implements ComponentInterface {
130144
});
131145
}
132146

133-
componentDidRender() {
134-
/**
135-
* After the first render completes, mark that we've rendered.
136-
* Setting this state property triggers a re-render, at which point
137-
* animations will be enabled. This ensures animations are disabled
138-
* only for the initial render, avoiding unwanted animations on load.
139-
*/
140-
if (!this.hasRendered) {
141-
this.hasRendered = true;
142-
}
143-
}
144147

145148
private setItemDefaults = () => {
146149
const ionItem = this.getSlottedHeaderIonItem();
@@ -239,6 +242,11 @@ export class Accordion implements ComponentInterface {
239242
const { contentEl, contentElWrapper } = this;
240243
if (initialUpdate || contentEl === undefined || contentElWrapper === undefined) {
241244
this.state = AccordionState.Expanded;
245+
/**
246+
* Mark that this accordion has been expanded at least once.
247+
* Do this even on initial expansion so future interactions animate.
248+
*/
249+
this.hasEverBeenExpanded = true;
242250
return;
243251
}
244252

@@ -250,6 +258,12 @@ export class Accordion implements ComponentInterface {
250258
cancelAnimationFrame(this.currentRaf);
251259
}
252260

261+
/**
262+
* Mark that this accordion has been expanded at least once.
263+
* This allows subsequent expansions to animate.
264+
*/
265+
this.hasEverBeenExpanded = true;
266+
253267
if (this.shouldAnimate()) {
254268
raf(() => {
255269
this.state = AccordionState.Expanding;
@@ -315,11 +329,15 @@ export class Accordion implements ComponentInterface {
315329
*/
316330
private shouldAnimate = () => {
317331
/**
318-
* Don't animate until after the first render cycle completes.
332+
* Don't animate until after the first user interaction.
319333
* This prevents animations on initial load when accordions
320-
* start in an expanded or collapsed state.
334+
* start in an expanded or collapsed state programmatically.
335+
*
336+
* Additionally, don't animate the very first expansion even if
337+
* hasInteracted is true. This handles edge cases like React StrictMode
338+
* where effects run twice and might incorrectly mark as interacted.
321339
*/
322-
if (!this.hasRendered) {
340+
if (!this.hasInteracted || !this.hasEverBeenExpanded) {
323341
return false;
324342
}
325343

@@ -418,6 +436,12 @@ export class Accordion implements ComponentInterface {
418436

419437
if (disabled || readonly) return;
420438

439+
/**
440+
* Mark that the user has interacted with the accordion.
441+
* This enables animations for all future state changes.
442+
*/
443+
this.hasInteracted = true;
444+
421445
if (accordionGroupEl) {
422446
/**
423447
* Because the accordion group may or may

0 commit comments

Comments
 (0)