bug: URL-synced inputs drop keystrokes and flicker during fast typing #34
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
Fast typing in URL-bound filter inputs (e.g. the document full-text search on
/, date filters on/conversations) causes:Root Cause
All filter pages follow the same two-sided sync pattern:
The race condition:
"a"→q = "a"→ 500 ms debounce fires →goto("/?q=a")→ navigation starts"b","c"→q = "abc"(local state is correct)?q=a) →data.filters.q="a"→$effectfires →qis overwritten back to"a""abc", launching another navigation — causing another overwrite cycleBecause the
$effectis unconditional (it always writesdata.filters→ state), any in-progress typing gets clobbered as soon as any navigation response arrives.Affected Pages / Inputs
/(documents)qoninput+ 500 ms debounce/conversationsonchange(less severe, fires on blur)/conversationsonclick(fires on click, not typing)The text search on
/is the most severely affected because it fires on every keystroke.Expected Behaviour
Characters typed at any speed must all be captured. The input must not jump back or lose text.
Proposed Fix
Option A — Skip
$effectsync while the input is focusedGuard the effect with a
document.activeElementcheck, or set adirtyflag while the user is editing and clear it after debounce fires.Option B — Debounce the
$effectsyncAdd a short guard (e.g. only sync if
q !== q_local) so the effect is a no-op when local state is already ahead of the URL.Option C — Replace
goto+$effectwithreplaceStateUse SvelteKit's
pushState/replaceState(shallow navigation) combined withinvalidate()for just the data fetch, instead of a fullgoto. This decouples URL updates from the reactive data cycle and eliminates the round-trip overwrite.Option C is the cleanest long-term solution because it removes the bidirectional coupling entirely.