Skip to content

fix: blur active element before component update during navigation#15452

Open
MathiasWP wants to merge 2 commits intosveltejs:mainfrom
MathiasWP:fix/blur-during-navigation-14575
Open

fix: blur active element before component update during navigation#15452
MathiasWP wants to merge 2 commits intosveltejs:mainfrom
MathiasWP:fix/blur-during-navigation-14575

Conversation

@MathiasWP
Copy link
Contributor

Closes #14575

Summary

  • Blur the active element before root.$set() so that blur/focusout handlers fire while the old component's data is still valid
  • Previously, root.$set() would null out component data before the browser fired blur on the old active element, causing TypeError: Cannot set properties of undefined in blur handlers that accessed data
  • Adds integration tests covering both goto() and popstate (back button) navigation paths

Edge case analysis

Safe — no breakage expected

  • Normal navigation: Focus was already going to be reset to <body> after navigation (reset_focus()). The blur just fires slightly earlier now.
  • keepFocus: true: Guarded by !keepfocus — no change in behavior.
  • No focused element / body focused: Guarded by activeElement !== document.body — no spurious blur fires.
  • Autofocus on target page: Unaffected — reset_focus() still runs after component update.

Edge cases (low risk)

  1. Blur handler triggers goto(): The existing nav_token system will abort the original navigation. This is already possible today — the fix just means blur fires slightly earlier, so such navigations could cancel more often. Very uncommon pattern and already fragile.
  2. Blur handler shows alert()/confirm(): These block the JS thread, delaying navigation. Same behavior as before, just fires at a slightly different time.
  3. Blur handler does heavy DOM mutation: Since blur fires before root.$set(), mutations could theoretically conflict — but Svelte's component update replaces the DOM anyway, so this is safe in practice.

Test plan

  • pnpm build passes
  • Integration tests pass: blur handler can access data during navigation (goto path)
  • Integration tests pass: blur handler can access data during popstate navigation (back button path)
  • pnpm -F @sveltejs/kit test:unit — no regressions (447 passed)

🤖 Generated with Claude Code

@changeset-bot
Copy link

changeset-bot bot commented Feb 27, 2026

🦋 Changeset detected

Latest commit: 3894e26

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@sveltejs/kit Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@svelte-docs-bot
Copy link

@MathiasWP MathiasWP force-pushed the fix/blur-during-navigation-14575 branch 2 times, most recently from f3bd85d to a0aad54 Compare February 27, 2026 22:05
…veltejs#14575)

Blur the active element before `root.$set()` so that blur/focusout
handlers fire while the old component's data is still valid. Previously,
data was nulled out before blur fired, causing TypeErrors in blur
handlers that accessed component data.

Guarded by `!keepfocus` and only applies when the active element is not
the body.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@MathiasWP MathiasWP force-pushed the fix/blur-during-navigation-14575 branch from a0aad54 to 2a3818c Compare February 27, 2026 22:08
The svelte-check type checker flags `window.__blur_test_result` as an
error since the property doesn't exist on the Window type. Use the same
`/** @type {any} */ (window)` cast pattern used in the test file.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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.

State referenced in onblur handler is undefined after navigation with async load

1 participant