Skip to content

Commit 1899b49

Browse files
authored
fix(refresher): prevent focus-related scroll jumps on refresh (#30636)
Issue number: resolves # --------- <!-- Please do not submit updates to dependencies unless it fixes an issue. --> <!-- Please try to limit your pull request to one type (bugfix, feature, etc). Submit multiple pull requests if needed. --> ## What is the current behavior? <!-- Please describe the current behavior that you are modifying. --> Currently, if you focus on something and then refresh with a refresher, the browser will try to scroll to what's focused after refreshing. This can be an unexpected and disrupting user experience. https://github.com/user-attachments/assets/3ef5999d-d104-422a-a6a9-4f478912f48a ## What is the new behavior? <!-- Please describe the behavior or changes that are being added by this PR. --> With these changes, we blur the active element to prevent the browser from trying to scroll back to something off screen after refreshing. Also, I did try to create regression tests for this, but playwright actually doesn't currently seem to make it possible as far as I can tell - that's actually what I spent most of my time on this issue trying to do. Looks like the only way to trigger the refresher with playwright uses mouse click events, which inherently blurs the active element. You need to use cursor events for this to work, because cursor events do not cause a blur on the active element. https://github.com/user-attachments/assets/bd1a3bfc-9b48-4b3f-b8dc-6959eefc9107 ## Does this introduce a breaking change? - [ ] Yes - [X] No <!-- If this introduces a breaking change: 1. Describe the impact and migration path for existing applications below. 2. Update the BREAKING.md file with the breaking change. 3. Add "BREAKING CHANGE: [...]" to the commit description when merging. See https://github.com/ionic-team/ionic-framework/blob/main/docs/CONTRIBUTING.md#footer for more information. --> ## Other information <!-- Any other information that is important to this PR such as screenshots of how the component looks before and after the change. --> **Current dev build:** ``` 8.7.3-dev.11755285796.12743331 ```
1 parent aadf06c commit 1899b49

File tree

1 file changed

+19
-0
lines changed

1 file changed

+19
-0
lines changed

core/src/components/refresher/refresher.tsx

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,15 @@ export class Refresher implements ComponentInterface {
253253
this.didRefresh = true;
254254
hapticImpact({ style: ImpactStyle.Light });
255255

256+
/**
257+
* Clear focus from any active element to prevent scroll jumps
258+
* when the refresh completes
259+
*/
260+
const activeElement = document.activeElement as HTMLElement;
261+
if (activeElement?.blur !== undefined) {
262+
activeElement.blur();
263+
}
264+
256265
/**
257266
* Translate the content element otherwise when pointer is removed
258267
* from screen the scroll content will bounce back over the refresher
@@ -733,6 +742,16 @@ export class Refresher implements ComponentInterface {
733742
// place the content in a hangout position while it thinks
734743
this.setCss(this.pullMin, this.snapbackDuration, true, '');
735744

745+
/**
746+
* Clear focus from any active element to prevent the browser
747+
* from restoring focus and causing scroll jumps after refresh.
748+
* This ensures the view stays at the top after refresh completes.
749+
*/
750+
const activeElement = document.activeElement as HTMLElement;
751+
if (activeElement?.blur !== undefined) {
752+
activeElement.blur();
753+
}
754+
736755
// emit "refresh" because it was pulled down far enough
737756
// and they let go to begin refreshing
738757
this.ionRefresh.emit({

0 commit comments

Comments
 (0)