fix(login): fix race in autofocus

This commit is contained in:
Edouard Vanbelle
2026-08-09 11:16:14 +02:00
parent 69c342f2ed
commit 107dbfc731
3 changed files with 21 additions and 1 deletions
@@ -8,7 +8,8 @@ const { fetchMeMock } = vi.hoisted(() => ({ fetchMeMock: vi.fn() }));
vi.mock('$lib/api/endpoints/auth', () => ({
fetchMe: () => fetchMeMock(),
tryRefresh: vi.fn(async () => false)
tryRefresh: vi.fn(async () => false),
bindDpopIfPossible: vi.fn(async () => false)
}));
import { session } from './session.svelte';
+18
View File
@@ -424,8 +424,26 @@
// avoids stealing focus from something else during the loading
// splash; the input-ref guard covers the render-order case where
// the effect fires before the DOM has the target.
//
// `activeElement` guard: if the user (or Playwright's `.fill()`, or
// browser autofill) already has focus in a form field, don't yank
// it away. Concrete bug this prevents: boot probes are slow → user
// types their email into the (initially unfocused) input → probes
// finish → `booting` flips false → this effect fires and refocuses
// the input, which resets the caret and can concatenate subsequent
// keystrokes onto the wrong field if the user was mid-tab. Mode-
// swap re-runs still refocus correctly because the old form's
// inputs unmount first, resetting `activeElement` to `<body>`.
$effect(() => {
if (booting) return;
const active = document.activeElement;
if (
active &&
active !== document.body &&
(active.tagName === 'INPUT' || active.tagName === 'TEXTAREA')
) {
return;
}
const target =
mode === 'login'
? loginIdentifierInput
+1
View File
@@ -21,6 +21,7 @@ vi.mock('$app/navigation', () => ({ goto }));
vi.mock('$app/state', () => ({ page: pageState }));
vi.mock('$lib/stores/session.svelte', () => ({ session }));
vi.mock('$lib/api/endpoints/auth', () => ({
bindDpopIfPossible: vi.fn().mockResolvedValue(false),
exchangeOidcCode: vi.fn(),
fetchMe: vi.fn(),
getOidcProviders: vi.fn(),