Summary
The PrimeVue <Menu> component renders each item as <li role="menuitem"> with aria-level, aria-setsize, and aria-posinset attributes. Per WAI-ARIA 1.2 §6.6 (menuitem role), those three attributes are not allowed on menuitem:
aria-level — applies to heading, listitem, row, treeitem only.
aria-setsize and aria-posinset — apply to article, listitem, option, radio, row, tab, treeitem only.
axe-core 4.x flags this as a critical aria-allowed-attr violation.
Versions
| Package |
Version observed |
primevue |
4.3.6 |
@primevue/nuxt-module |
4.3.6 / 4.3.9 |
@primevue/forms |
4.3.9 |
axe-core (via axe-playwright-python) |
bundled with 0.1.7 (axe-core 4.10) |
Confirmed against two independent Nuxt 3/4 + PrimeVue applications (anonymised: "FrontendA", "FrontendB"); the violation fires on every <Menu> instance, with one violation per model[] entry.
Reproducing example
The simplest repro is the canonical PrimeVue Menu demo. Any consumer of <Menu :model="items"> reproduces this — there's no escape via slot overrides because the offending attributes are emitted by the Menu's own rendered <li> wrapper, not by user-supplied templates.
<script setup lang="ts">
import Menu from 'primevue/menu'
const items = [
{ label: 'Refresh' },
{ label: 'Export' },
{ label: 'Delete' },
]
</script>
<template>
<Menu :model="items" />
</template>
Then in browser console (after Menu is mounted):
axe.run({ runOnly: { type: 'tag', values: ['wcag2a','wcag2aa'] } })
.then(r => console.log(r.violations.filter(v => v.id === 'aria-allowed-attr')))
Yields one aria-allowed-attr violation per item, with target of the form #pv_id_<n>_<m> (or class-based selectors when the auto-id is suppressed) and failureSummary:
ARIA attribute is not allowed: aria-level="1" aria-setsize="3" aria-posinset="1"
Detected violation HTML (verbatim from axe nodes)
<li id="pv_id_1_11_0"
style=""
class="..."
role="menuitem"
aria-label="..."
aria-level="1"
aria-setsize="3"
aria-posinset="1"
data-pc-section="item"
...>
Suggested fix
Two equivalent paths:
- Drop the three attributes from
<li role="menuitem"> — they convey no information that isn't already implicit in the menubar/menu structure or stated more correctly via aria-orientation on the parent menu.
- Change the role — if the hierarchy semantics matter for the implementation, switch the wrapping role to
treeitem (with a parent tree) or listitem (with a parent list). But this changes downstream keyboard-nav semantics, so option 1 is less invasive.
Affected files (from a quick scan of the PrimeVue source as of 4.3.x):
packages/primevue/src/menu/Menu.vue — MenuItem.vue template
packages/primevue/src/tieredmenu/TieredMenu.vue — same root <li> shape
packages/primevue/src/contextmenu/ContextMenu.vue — likely identical
packages/primevue/src/menubar/Menubar.vue — should be checked too
Workaround
Until a fix lands, consumers can use :pt to strip the disallowed attributes:
<Menu
:model="items"
:pt="{
item: ({ context }) => ({
'aria-level': null,
'aria-setsize': null,
'aria-posinset': null,
})
}"
/>
This is fragile (relies on :pt honouring null to remove attrs, which isn't formally guaranteed across PrimeVue minor releases).
Why this matters
These violations are critical-impact under axe's severity scheme — they break screen reader expectations for menu navigation. Two production frontends shipping accessibility-compliant UIs cannot pass an automated WCAG 2.1 AA audit while using <Menu> as-shipped.
Tracking
This issue is being tracked on the consumer side at:
vioxen/quanta-id-web#85 (companion issue + remediation work for the broader a11y sweep)
Happy to test a fix or PR a candidate diff against the components above if maintainers prefer that route.
Summary
The PrimeVue
<Menu>component renders each item as<li role="menuitem">witharia-level,aria-setsize, andaria-posinsetattributes. Per WAI-ARIA 1.2 §6.6 (menuitem role), those three attributes are not allowed onmenuitem:aria-level— applies toheading,listitem,row,treeitemonly.aria-setsizeandaria-posinset— apply toarticle,listitem,option,radio,row,tab,treeitemonly.axe-core 4.x flags this as a critical
aria-allowed-attrviolation.Versions
primevue@primevue/nuxt-module@primevue/formsaxe-core(viaaxe-playwright-python)Confirmed against two independent Nuxt 3/4 + PrimeVue applications (anonymised: "FrontendA", "FrontendB"); the violation fires on every
<Menu>instance, with one violation permodel[]entry.Reproducing example
The simplest repro is the canonical PrimeVue Menu demo. Any consumer of
<Menu :model="items">reproduces this — there's no escape via slot overrides because the offending attributes are emitted by the Menu's own rendered<li>wrapper, not by user-supplied templates.Then in browser console (after Menu is mounted):
Yields one
aria-allowed-attrviolation per item, withtargetof the form#pv_id_<n>_<m>(or class-based selectors when the auto-id is suppressed) andfailureSummary:Detected violation HTML (verbatim from axe nodes)
Suggested fix
Two equivalent paths:
<li role="menuitem">— they convey no information that isn't already implicit in the menubar/menu structure or stated more correctly viaaria-orientationon the parent menu.treeitem(with a parenttree) orlistitem(with a parentlist). But this changes downstream keyboard-nav semantics, so option 1 is less invasive.Affected files (from a quick scan of the PrimeVue source as of 4.3.x):
packages/primevue/src/menu/Menu.vue—MenuItem.vuetemplatepackages/primevue/src/tieredmenu/TieredMenu.vue— same root<li>shapepackages/primevue/src/contextmenu/ContextMenu.vue— likely identicalpackages/primevue/src/menubar/Menubar.vue— should be checked tooWorkaround
Until a fix lands, consumers can use
:ptto strip the disallowed attributes:This is fragile (relies on
:pthonouringnullto remove attrs, which isn't formally guaranteed across PrimeVue minor releases).Why this matters
These violations are critical-impact under axe's severity scheme — they break screen reader expectations for menu navigation. Two production frontends shipping accessibility-compliant UIs cannot pass an automated WCAG 2.1 AA audit while using
<Menu>as-shipped.Tracking
This issue is being tracked on the consumer side at:
vioxen/quanta-id-web#85(companion issue + remediation work for the broader a11y sweep)Happy to test a fix or PR a candidate diff against the components above if maintainers prefer that route.