I ran into this while comparing #23024 and #23027 (the two PRs that replaced document.activeElement with the new getActiveElement() helper across VDialog, VField, VFileInput, VTextField, VTextarea, useActivator, hotkey and VCommandPalette) against the rest of the codebase.
VSelect.tsx's onAfterEnter still has the old check:
// VSelect.tsx
function onAfterEnter () {
if (props.eager) {
vVirtualScrollRef.value?.calculateVisibleItems()
}
if (!listRef.value || !isFocused.value) return
// VMenu re-dispatches ArrowUp/Down after open and already moved focus to next/prev
if (listRef.value.$el?.contains(document.activeElement)) return
...
Inside a shadow root, document.activeElement only ever resolves to the shadow host, not the actual focused element inside the shadow tree, same mechanism #23027 fixed for VDialog/VOverlay/VTextField etc. So this guard reports false even when focus is legitimately inside the list, and the fallback focus-move logic right below it fires when it shouldn't, causing the same kind of focus fight the other components were just fixed for, specifically for VSelect (and by extension VAutocomplete/VCombobox, which build on it).
I grepped the repo for remaining document.activeElement usage after those two PRs merged (document.activeElement repo:vuetifyjs/vuetify). This is the only production source hit besides useFocusRepair.ts, which #23027's own description already calls out as not needing a change, and I checked that one too: it compares against document.body, not a shadow-scoped container, so it's genuinely fine as-is. VSelect.tsx is the one that was missed.
Repro: render VSelect inside a defineCustomElement-wrapped shadow root (the harness from #23027's own repro page works for this), open the menu, use arrow keys to move focus into the list, and watch the fallback focus-move branch fire even though focus is already correctly inside the list.
Fix should be the same one-line swap as the other components: getActiveElement() (from @/util) instead of document.activeElement.
I ran into this while comparing #23024 and #23027 (the two PRs that replaced
document.activeElementwith the newgetActiveElement()helper across VDialog, VField, VFileInput, VTextField, VTextarea, useActivator, hotkey and VCommandPalette) against the rest of the codebase.VSelect.tsx'sonAfterEnterstill has the old check:Inside a shadow root,
document.activeElementonly ever resolves to the shadow host, not the actual focused element inside the shadow tree, same mechanism #23027 fixed for VDialog/VOverlay/VTextField etc. So this guard reportsfalseeven when focus is legitimately inside the list, and the fallback focus-move logic right below it fires when it shouldn't, causing the same kind of focus fight the other components were just fixed for, specifically forVSelect(and by extensionVAutocomplete/VCombobox, which build on it).I grepped the repo for remaining
document.activeElementusage after those two PRs merged (document.activeElement repo:vuetifyjs/vuetify). This is the only production source hit besidesuseFocusRepair.ts, which #23027's own description already calls out as not needing a change, and I checked that one too: it compares againstdocument.body, not a shadow-scoped container, so it's genuinely fine as-is.VSelect.tsxis the one that was missed.Repro: render
VSelectinside adefineCustomElement-wrapped shadow root (the harness from #23027's own repro page works for this), open the menu, use arrow keys to move focus into the list, and watch the fallback focus-move branch fire even though focus is already correctly inside the list.Fix should be the same one-line swap as the other components:
getActiveElement()(from@/util) instead ofdocument.activeElement.