Skip to content
svelte-vitals
English
Esc
navigateopen⌘Jpreview
On this page

a11y/disallowed-aria-props · ARIA attribute not allowed on this role

An aria-* attribute the element's role does not support is ignored; one the role prohibits, such as a name on a bare div, is a name that is not exposed.

Severity: warning · Category: a11y

What it checks

Flags an aria-* attribute that the element’s role either prohibits or does not own, judged against the ARIA 1.3 role tables in component source.

Which role is judged:

  • An explicit role, taking its first concrete token, as a browser resolves role="switch checkbox". A role ARIA does not define is a11y/invalid-role’s finding, not this one; a DPUB-ARIA role (doc-toc, …) gets no judgment, since the role tables this rule reads do not cover DPUB.
  • Otherwise the element’s implicit role, and for the elements whose implicit role depends on context (<a> is link only with href, <img alt=""> is presentation, <input> is whatever its type says), every role the element could have. A judgment is made only when it holds under all of them. So <div aria-label> fires (a <div> is generic everywhere, and generic does not take a name), while <a aria-label>, <img aria-label> and <input aria-checked> do not. <input> is effectively unjudgeable for any non-global attribute here; the Svelte compiler’s a11y_role_supports_aria_props_implicit covers <input type="text" aria-checked>.
  • An expression role, or a spread with no literal role, leaves the role unknowable: no finding.

Two kinds of finding, with different messages:

  • Prohibited. aria-label, aria-labelledby or aria-braillelabel on an element whose role does not take a name (<div>, <span>, <p>, <code>, <label>, <time>, …), or any attribute a role’s table lists as prohibited (aria-roledescription on generic). Message: “aria-label is prohibited on <div> — its role does not take a name”.
  • Not supported. An attribute absent from the role’s table: aria-checked on role="button", aria-level on a <span>. Message: “aria-level is not supported by role generic”.
<div aria-label="Breadcrumb">Home / Gallery</div>

<div role="button" tabindex="0" aria-checked="true">Toggle</div>

Not flagged:

  • An attribute a11y/unknown-aria-attribute already reports: one typo, one finding.
  • The (role, attribute) pairs the ARIA 1.3 tables no longer list but the Svelte compiler’s data still accepts (aria-level on listitem, aria-expanded on listbox, …). Where the compiler and this rule would disagree on the same markup, the compiler wins.
  • <address aria-label> and <hgroup aria-label>: the dataset marks both as not taking a name, but the ARIA-in-HTML specification and axe give both role=group, which does. This rule follows the specification.
  • Anything a value could fix (a11y/invalid-aria-value) or a missing required attribute (a11y/required-aria-props).

Overlap with the Svelte compiler. For explicit roles and the implicit roles the compiler maps, a11y_role_supports_aria_props / _implicit report the not supported case too, and this rule agrees with it. The compiler is silent on the prohibited case: <div aria-label> compiles without a warning, and that is the case that appears in real code.

Where axe differs. axe’s aria-prohibited-attr grades a prohibited name as needs review when the element has text content and serious only when it does not, and exempts a name whose nearest ancestor role is a widget. This rule reports all of them: ARIA prohibits the attribute on the role regardless of what else names the element. <label> is the one to know about. The specification prohibits a name on it only when it is exposed as generic; the dataset and axe both prohibit it unconditionally, and <label for=… aria-label="close sidebar"> will fire.

Why it matters

An unsupported aria-* attribute is dropped by assistive technology, so the state the author meant to convey is not conveyed. A prohibited one is worse: aria-label on a bare <div> looks, in the source, like a labelled region, and screen readers announce nothing for it. The label exists only in the author’s mental model.

How to fix

Give the element a role that supports the attribute, or move the attribute to the element that owns the semantics:

<nav aria-label="Breadcrumb">Home / Gallery</nav>

<div role="switch" tabindex="0" aria-checked="true">Toggle</div>

Mode differences

None. This rule reads source, the same .svelte and .ts files, everywhere it runs. The CLI, the Vite plugin’s build pass, and the live dashboard’s static baseline all report it identically, and the rendered-HTML pass never re-evaluates it. Scoping a run with --route skips it: component-scoped rules have no route to attribute a finding to.

Disabling

Silence a single element with <!-- svelte-vitals-disable-next-line a11y/disallowed-aria-props -->, or turn the rule off:

export default {
  rules: {
    'a11y/disallowed-aria-props': 'off'
  }
};