ADA Compliance Professionals

    ARIA attributes must match role specs

    Last updated:

    Who it helps:
    Blind
    Standard:
    WCAG 2.2 Level A

    ARIA attributes must not conflict with native states or roles

    Only use ARIA attributes where the specification allows; never override native semantics. Issues often appear when aria-checked is added to a native checkbox or when treegrid-only attributes (aria-level, aria-posinset, aria-setsize, aria-expanded) are applied to rows in plain tables or grids. These mistakes confuse assistive technologies and create mismatched states.

    Why It Matters

    Assistive technologies rely on consistent name, role, and state information. If ARIA contradicts the underlying element, users hear conflicting announcements or miss key states. For example, a screen reader may announce a checkbox as checked while the browser exposes it as unchecked, or ignore hierarchical row info that only applies in a treegrid.

    This directly affects blind and low-vision users who navigate by semantics, and can also confuse voice control users who issue commands based on roles and states. It relates to WCAG 2.2 Success Criterion 4.1.2 (Name, Role, Value).

    Common Causes

    • Setting aria-checked on a native input type="checkbox" instead of using the checked state.
    • Copying ARIA patterns without verifying which roles/attributes are allowed on the element.
    • Applying aria-level, aria-posinset, aria-setsize, or aria-expanded to <tr> or role="row" inside a regular table or grid.
    • Building a custom checkbox without role, state management, or keyboard handling.
    • Mixing native semantics (table) with widget semantics (treegrid) in the same component.

    How to Fix

    Native HTML checkboxes

    • Remove aria-checked from input type="checkbox".
    • Use the checked attribute/property and keep it in sync with the UI state.
    • Ensure the checkbox has a visible and programmatic label via <label>, aria-label, or aria-labelledby.

    Custom (non-native) checkbox

    • Use a focusable element (e.g., <button> or <div tabindex="0">) with role="checkbox".
    • Manage the state with aria-checked="true"/"false" and update it on interaction.
    • Support keyboard: Space toggles the state; focus is visible.
    • Keep the visual state, aria-checked, and any internal data model synchronized.
    • Provide a clear label via text content or aria-labelledby.

    Row hierarchy attributes (treegrid only)

    • Only use aria-level, aria-posinset, aria-setsize, and aria-expanded when the parent widget is a treegrid (container has role="treegrid").
    • Mark rows with role="row" and cells with role="gridcell" (or rowheader when appropriate).
    • Apply aria-level/aria-posinset/aria-setsize on the row to express hierarchy and set membership.
    • Use aria-expanded on the row (or the appropriate first-column gridcell) to indicate collapsed/expanded state.
    • If you are not implementing a hierarchical grid, remove these attributes.

    Recommendation: Prefer native HTML controls where possible. Only add ARIA when necessary and supported for the element’s role.

    How to Test

    • Keyboard (checkboxes):
    • Tab to each checkbox.
    • Confirm the focus indicator is visible.
    • Press Space to toggle. Verify visual and programmatic state change together.
    • Screen reader (checkboxes):
    • Navigate to the checkbox. Verify it is announced as "checkbox" with the correct checked/unchecked state.
    • Toggle and confirm the announcement updates.
    • Keyboard (treegrid):
    • Ensure rows are reachable with Tab (or arrow keys within the grid as appropriate).
    • If expandable, confirm keyboard toggles update aria-expanded and the visible content.
    • Screen reader (treegrid):
    • Verify the container is announced as a grid/treegrid.
    • Confirm level is announced where appropriate and that expanded/collapsed states are read.
    • Mobile/touch:
    • Check that custom checkboxes can be activated by touch and have adequate target size (recommendation: at least 24x24 CSS px).
    • Code review:
    • Inspect the accessibility tree in DevTools.
    • Confirm no aria-checked is present on native checkboxes.
    • Verify aria-level/aria-posinset/aria-setsize/aria-expanded appear only within a treegrid context.

    Good Example

    Native checkbox using the browser’s state:

    HTML
    <label>
      <input type="checkbox" checked>
      Receive product updates by email
    </label>

    Treegrid row using hierarchy attributes correctly:

    HTML
    <div role="treegrid" aria-label="Downloads">
      <div role="row" aria-level="1" aria-setsize="2" aria-posinset="1" aria-expanded="false">
        <div role="gridcell">My Downloads</div>
      </div>
    </div>

    Bad Example

    ARIA overriding a native checkbox state:

    HTML
    <label>
      <input type="checkbox" aria-checked="true">
      Receive product updates by email
    </label>
    
    Hierarchy attributes on a plain table (not a treegrid):
    HTML
    <table>
      <tr aria-level="1" aria-expanded="false">
        <td>My Downloads</td>
      </tr>
    </table>

    Quick Checklist

    • Do not set aria-checked on input type="checkbox".
    • For custom checkboxes, use role="checkbox", aria-checked, and Space to toggle.
    • Keep visual state, ARIA state, and data model in sync.
    • Use aria-level/aria-posinset/aria-setsize/aria-expanded only inside a role="treegrid".
    • Do not apply treegrid-only attributes to plain tables or grids.
    • Provide clear, programmatic labels for all controls and rows.
    • Validate allowed roles and properties with the accessibility tree and linters.