Commit 5bceab6
fix(Listbox): prevent page scroll on mount caused by changeHighlight (#2666)
* fix(Listbox): prevent page scroll on mount caused by changeHighlight
The immediate watcher on modelValue calls highlightSelected() on mount,
which triggers el.focus() and el.scrollIntoView(). When the Listbox is
below the fold, this scrolls the entire page down without user interaction.
Pass preventScroll: true to focus() and skip scrollIntoView on the initial
mount invocation, while preserving scroll behavior for subsequent
programmatic changes and all user-driven highlights.
* fix: skip focus and scrollIntoView on first changeHighlight call
Simplify the approach: use a one-shot isInitialHighlight flag that
skips focus() and scrollIntoView() on the very first changeHighlight
invocation (the mount highlight). This covers all code paths including
virtual listbox hooks without any timing dependencies (no rAF, no
window API).
* fix(Listbox): release initial-highlight guard after mount cycle
The one-shot guard skipped focus/scroll on the first changeHighlight call
ever, which could fire at the wrong time for deferred-render consumers
(Combobox/Autocomplete open their listbox later). Release the guard on the
nextTick after the initial mount highlight instead, so only the mount
highlight is suppressed and every later highlight scrolls/focuses normally.
Add tests: Listbox must not scroll the page or steal focus on mount but must
do so on interaction, and Combobox must scroll the selected item into view on
first open.
* test(Listbox): drop unrelated Combobox test and story change
The Combobox test didn't discriminate this fix (it passes on the old
behavior too) and the story tweak only existed to support it. Keep the PR
scoped to the Listbox page-scroll-on-mount fix and its mount test.
* refactor(Listbox): thread scroll intent instead of mount-release guard
Replaces the `isInitialHighlight` flag (released on a later `nextTick`)
with an explicit `scroll` argument threaded through `highlightSelected()`.
The "is this the mount highlight?" decision is now flipped synchronously
in the modelValue watcher, so suppression travels with the call as an
argument rather than via shared state cleared on a subsequent tick — it
no longer depends on nextTick ordering, which differs between a client
mount and SSR hydration.
Behaviour is unchanged: the mount highlight only sets the roving-tabindex
target (no focus, no page scroll), while user navigation and a Combobox
opening its dropdown still focus/scroll as before. `changeHighlight` is
restored to its original form (it already accepts scrollIntoView/focus).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: zernonia <zernonia@gmail.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>1 parent 8212fa5 commit 5bceab6
2 files changed
Lines changed: 52 additions & 4 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
132 | 132 | | |
133 | 133 | | |
134 | 134 | | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
135 | 170 | | |
136 | 171 | | |
137 | 172 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
324 | 324 | | |
325 | 325 | | |
326 | 326 | | |
327 | | - | |
| 327 | + | |
328 | 328 | | |
329 | 329 | | |
330 | 330 | | |
| |||
339 | 339 | | |
340 | 340 | | |
341 | 341 | | |
| 342 | + | |
| 343 | + | |
| 344 | + | |
| 345 | + | |
342 | 346 | | |
343 | | - | |
| 347 | + | |
344 | 348 | | |
345 | | - | |
| 349 | + | |
346 | 350 | | |
347 | 351 | | |
348 | 352 | | |
| 353 | + | |
| 354 | + | |
| 355 | + | |
| 356 | + | |
| 357 | + | |
| 358 | + | |
| 359 | + | |
349 | 360 | | |
350 | 361 | | |
351 | 362 | | |
| 363 | + | |
| 364 | + | |
352 | 365 | | |
353 | | - | |
| 366 | + | |
354 | 367 | | |
355 | 368 | | |
356 | 369 | | |
| |||
0 commit comments