diff --git a/frontend/src/lib/actions/focus-trap.ts b/frontend/src/lib/actions/focus-trap.ts index c7d7f77..150f68e 100644 --- a/frontend/src/lib/actions/focus-trap.ts +++ b/frontend/src/lib/actions/focus-trap.ts @@ -64,11 +64,16 @@ export function focusTrap( node.addEventListener('keydown', onKeyDown); if (opts.autoFocus !== false) { - // Defer one frame so the element is fully laid out (sheets animate in). + // Focus the container synchronously on mount so the trap owns the keyboard + // immediately — otherwise an Escape pressed before the deferred focus below + // lands on an element *outside* the node, where this node-scoped listener + // never sees it (the keystroke is silently dropped). Then defer one frame to + // move focus onto the first control once the sheet has laid out / animated in. + if (!node.hasAttribute('tabindex')) node.setAttribute('tabindex', '-1'); + node.focus({ preventScroll: true }); requestAnimationFrame(() => { const list = focusables(node); const target = list[0] ?? node; - if (!node.hasAttribute('tabindex')) node.setAttribute('tabindex', '-1'); target.focus({ preventScroll: true }); }); } diff --git a/frontend/src/routes/recover/+page.svelte b/frontend/src/routes/recover/+page.svelte index 40de203..d2864ad 100644 --- a/frontend/src/routes/recover/+page.svelte +++ b/frontend/src/routes/recover/+page.svelte @@ -1,14 +1,23 @@