Fix Missing Required ARIA Attributes

Learn how to fix aria-required-attr issues in Lighthouse accessibility audits
Harlan WiltonHarlan Wilton4 min read Published

ARIA roles without their required attributes leave screen reader users guessing about element state.

What's Happening

When you assign an ARIA role to an element, certain attributes become mandatory. These required attributes tell assistive technologies the current state of the element. Without them, a screen reader might announce "checkbox" but have no way to convey whether it's checked or unchecked.

Diagnose

  1. Open Chrome DevTools (F12)
  2. Go to Elements panel
  3. Find the flagged element using the selector from Lighthouse
  4. Check which role attribute is present
  5. Compare against the required attributes for that role

Common roles and their required attributes:

  • role="checkbox" requires aria-checked
  • role="combobox" requires aria-expanded and aria-controls
  • role="slider" requires aria-valuenow, aria-valuemin, aria-valuemax
  • role="scrollbar" requires aria-controls, aria-valuenow, aria-valuemin, aria-valuemax
  • role="heading" requires aria-level

Fix

1. Add Missing Attributes

For a custom checkbox missing aria-checked:

<!-- Before: Missing required attribute -->
<div role="checkbox" tabindex="0">
  Accept terms
</div>

<!-- After: Complete with required attribute -->
<div role="checkbox" aria-checked="false" tabindex="0">
  Accept terms
</div>

Update the attribute dynamically when state changes:

checkbox.addEventListener('click', () => {
  const isChecked = checkbox.getAttribute('aria-checked') === 'true'
  checkbox.setAttribute('aria-checked', !isChecked)
})

2. Use Native HTML Elements

Native elements handle required states automatically:

<!-- Native checkbox - no ARIA needed -->
<label>
  <input type="checkbox" name="terms">
  Accept terms
</label>

<!-- Native slider - no ARIA needed -->
<input type="range" min="0" max="100" value="50">

3. Fix Slider/Range Controls

Custom sliders need multiple attributes:

<!-- Complete slider implementation -->
<div
  role="slider"
  aria-valuenow="50"
  aria-valuemin="0"
  aria-valuemax="100"
  aria-label="Volume"
  tabindex="0"
>
  <div class="slider-thumb"></div>
</div>

Framework Examples

In Vue/Nuxt, bind required attributes reactively:
<script setup>
const props = defineProps(['label'])
const isChecked = ref(false)
</script>

<template>
  <div
    role="checkbox"
    :aria-checked="isChecked"
    tabindex="0"
    @click="isChecked = !isChecked"
    @keydown.space.prevent="isChecked = !isChecked"
  >
    {{ label }}
  </div>
</template>

Verify the Fix

  1. Re-run Lighthouse accessibility audit
  2. Test with a screen reader:
    • Navigate to the element
    • Confirm the role AND state are announced
  3. Interact with the element and verify state changes are announced

Common Mistakes

  • Adding attributes with empty valuesaria-checked="" is invalid. Use "true" or "false".
  • Forgetting to update dynamic state — Initial value is set but never updated on interaction.
  • Using ARIA when native HTML works — Native <input type="checkbox"> handles all states automatically.
  • Wrong attribute for the role — Each role has specific required attributes. Check the WAI-ARIA specification.

Required attribute issues often appear alongside:

Test Your Entire Site

Missing required ARIA attributes often appear in reusable components across your site. Unlighthouse scans every page automatically, finding all instances where roles lack their required attributes, so you can fix components once and improve accessibility everywhere.