Repository navigation
[Bug Report][4.1.9] a11y: VMenu and VSelect/VAutocomplete/VCombobox reference an aria-controls/aria-owns id absent from the document while closed #23119
Description
Environment
Vuetify Version: 4.1.9
Vue Version: 3.5.38
Browsers: Chrome
OS: Linux
Steps to reproduce
Render a closed select or menu and inspect the served or hydrated DOM — no interaction needed, the defect is the closed state:
<v-select :items="['a', 'b']" label="Sort by" />
<v-menu>
<template #activator="{ props }">
<v-btn v-bind="props" text="Open" />
</template>
<v-list :items="['a']" />
</v-menu>Run the page through the W3C validator (https://validator.w3.org/nu) or axe.
Expected Behavior
ARIA id references resolve, or are not emitted. The APG combobox pattern is explicit that the reference is only needed while the popup is up:
Note that
aria-controlsonly needs to be set when the popup is visible. However, it is valid to reference an element that is not visible.
Referencing a hidden element is valid — referencing an id that is not in the document is not. In the menu button pattern, aria-controls is optional altogether.
Actual Behavior
The references are emitted unconditionally:
VMenu.tsx— theactivatorPropscomputed puts'aria-controls': id.value, 'aria-owns': id.valueon the activator.composables/menuActivator.ts—ariaControls = toRef(() => menuId.value), rendered asaria-controlson the input ofVSelect,VAutocompleteandVCombobox.
But the element carrying that id only exists while the overlay has content: useLazy's hasContent is isBooted || eager || active, and onAfterLeave resets isBooted when not eager. So before the first open — and again after every close — the id is absent from the document, and every closed select/menu on the page fails validation:
The
aria-controlsattribute must point to an element in the same document.
(severity: error, one per attribute per closed select/menu; axe reports the same as aria-valid-attr-value. European accessibility audits — RGAA / EN 301 549 — flag each occurrence.)
Prior reports
- [Bug Report][3.4.9] Invalid aria-owns in v-menu activator. #19250 reported exactly this (axe flagging
aria-owns="v-menu-759"on the activator) and was closed as a duplicate of [Bug Report][3.4.10] VSelect not adding corresponding id to its menu #19054 — but [Bug Report][3.4.10] VSelect not adding corresponding id to its menu #19054 only gave the id to the open menu. The closed state was never addressed. - [Bug Report][3.11.7] Menu items in v-menu have no accessible labels with VoiceOver on Safari (probably aria-owns issue) #22540 (open) reports that
aria-ownson the activator breaks VoiceOver's announcement of menu item labels — one more reason not to advertise it while nothing is open.
Suggested fix
Emit the references only while the popup is open, which is the APG-documented pattern:
// composables/menuActivator.ts
- const ariaControls = toRef(() => menuId.value)
+ const ariaControls = toRef(() => toValue(isOpen) ? menuId.value : undefined) // VMenu.tsx
- 'aria-controls': id.value,
- 'aria-owns': id.value,
+ 'aria-controls': isActive.value ? id.value : undefined,
+ 'aria-owns': isActive.value ? id.value : undefined,One existing test pins the current behaviour and would need its closed-state assertion moved after the open: VSelect.spec.browser.tsx › "should have reactive accessibility attributes" asserts aria-controls while expanded: false — i.e. it asserts the dangling reference.
VTooltip has the same shape ('aria-describedby': id.value unconditional while the tooltip content is unmounted) — happy to cover it in the same PR or leave it for a follow-up.
Our current userland workaround is eager defaults on the four components so the overlay stays mounted and the ids always resolve — viable because the lists are virtualised, but it mounts overlays nobody may ever open.
Happy to open a PR if this approach sounds right.
Activity
waterWang commentedon Aug 16, 2026
I've submitted PR #23128 to fix this.
Changes
VMenu.tsx:activatorPropsnow spreadsaria-controls/aria-ownsonly whenisActive.valueis truecomposables/menuActivator.ts:ariaControlsnow resolves toundefinedwhile the menu is closed, so the attribute is not rendered onVSelect/VAutocomplete/VComboboxinputsValidation
Per the ARIA combobox pattern:
Referencing a hidden element is valid — referencing an id that is not in the document is not. The fix ensures the popup id is only referenced while the menu is actually open.