Fix Missing Required ARIA Attributes
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
- Open Chrome DevTools (F12)
- Go to Elements panel
- Find the flagged element using the selector from Lighthouse
- Check which
roleattribute is present - Compare against the required attributes for that role
Common roles and their required attributes:
role="checkbox"requiresaria-checkedrole="combobox"requiresaria-expandedandaria-controlsrole="slider"requiresaria-valuenow,aria-valuemin,aria-valuemaxrole="scrollbar"requiresaria-controls,aria-valuenow,aria-valuemin,aria-valuemaxrole="heading"requiresaria-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
<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
- Re-run Lighthouse accessibility audit
- Test with a screen reader:
- Navigate to the element
- Confirm the role AND state are announced
- Interact with the element and verify state changes are announced
Common Mistakes
- Adding attributes with empty values —
aria-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.
Related Issues
Required attribute issues often appear alongside:
- Valid ARIA Attributes — Check spelling before checking completeness
- ARIA Hidden Focus — Both involve proper ARIA usage on interactive elements
- Button Name — Custom buttons need both names and proper ARIA states
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.