The first rule of ARIA is: don't use it if native HTML already provides what you need. This lesson covers when ARIA genuinely earns its place, how boolean props become DOM strings, the difference between aria-label and aria-labelledby, and why incorrect ARIA is worse than none.
1The First Rule of ARIA Is: Don't
ARIA attributes describe semantics native HTML can't express on its own, but the official first rule of ARIA use states: if a native HTML element or attribute already provides the needed behavior, use that instead of adding ARIA roles to a generic element.
2When ARIA Genuinely Earns Its Keep
ARIA is essential for interface patterns with no native HTML equivalent ā a tab panel, a filtering combobox, a toast notification. In these cases, attributes like role, aria-selected, and aria-expanded communicate state and structure that would otherwise be entirely invisible to assistive technology.
3Boolean Props Need String Values in JSX
ARIA attributes are HTML attributes underneath, so React renders a JavaScript boolean passed to one, like aria-expanded={isOpen}, as the actual string 'true' or 'false' in the resulting DOM ā the expected behavior, worth understanding as attribute conversion rather than a literal boolean.
4aria-label vs. aria-labelledby
aria-label supplies a text string directly for an element with no visible text, like an icon-only button. aria-labelledby instead references the id of another element already on the page, reusing its visible text as the label ā appropriate when a heading already visually serves that purpose.
5Invalid ARIA Is Worse Than No ARIA
A wrong role or a mismatched attribute doesn't fail silently ā it can actively mislead assistive technology by announcing something inaccurate about the element. Linting tools like eslint-plugin-jsx-a11y catch many invalid ARIA patterns automatically, and when uncertain, removing ARIA is safer than guessing.
6Step-by-Step Breakdown
The First Rule of ARIA Is: Don't. ARIA (Accessible Rich Internet Applications) attributes describe semantics HTML can't express on its own. But the official first rule of ARIA use is: if a native HTML element or attribute already provides the behavior you need, use that instead of adding ARIA to a generic element.
When ARIA Genuinely Earns Its Keep. ARIA is essential for interface patterns HTML has no native equivalent for ā a tab panel, a combobox with live filtering, a toast notification. In these cases, role, aria-selected, aria-expanded, and similar attributes communicate state and structure that would otherwise be invisible to assistive technology.
Why is role="tab" combined with aria-selected genuinely necessary for a tabs widget, unlike a plain button?
- āHTML has no native tab element, so ARIA is the only way to express this pattern
- āIt's purely a styling hook with no semantic meaning
Boolean Props Need String Values in JSX. Most React props accept real JavaScript booleans (disabled={true}), but ARIA attributes are HTML attributes underneath, and React passes them through as strings ā aria-expanded={true} renders as aria-expanded="true" in the DOM, which is exactly what's expected, but it's worth knowing that's genuinely a string, not a boolean, once it hits the DOM.
aria-label vs. aria-labelledby. aria-label supplies a text string directly for an element with no visible text (like an icon-only close button). aria-labelledby instead references the id of ANOTHER element already on the page whose text should be used as the label ā useful when a heading already visually serves that purpose.
For an icon-only close button (ā) with no visible text at all, which attribute should you use to give it an accessible name?
- āaria-label, providing the text directly since there's nothing visible to reference
- āaria-labelledby, referencing some other element's id
Invalid ARIA Is Worse Than No ARIA. A wrong role or a mistyped attribute value doesn't just fail silently ā it can actively mislead assistive technology, announcing something completely inaccurate about the element. Run eslint-plugin-jsx-a11y to catch invalid ARIA usage automatically, and when in doubt, remove ARIA rather than guess.
Mastery Achieved. You now understand ARIA in React: preferring native HTML first, using ARIA where it genuinely fills a gap, how boolean props become DOM strings, choosing between aria-label and aria-labelledby, and why incorrect ARIA is worse than none at all. Next, you'll learn focus management for controlling exactly where keyboard focus goes during dynamic UI changes.
Level Up š
Advanced cheat sheets, SEO tricks, and interview prep for this topic.
Browser Support
ARIA support depends on both browser and screen reader; test with a real assistive technology combination.
Fully supported, paired with NVDA on Windows.
Fully supported, paired with VoiceOver on macOS.
Fully supported.
Accessibility (A11y)
1ARIA Changes Semantics, Not Appearance or Behavior
Adding a role or ARIA attribute doesn't automatically give an element keyboard behavior or styling ā those must still be implemented manually; ARIA only affects what's communicated to assistive technology.
SEO Implications
- 1
ARIA Has Minimal Direct SEO Effect but Signals Content Quality
Search engines don't heavily weight ARIA attributes for ranking directly, but well-structured, accessible markup tends to correlate with generally higher-quality, better-structured content overall.
Best Practices
Verify Every ARIA role Has Its Required Attributes
Many ARIA roles have required accompanying attributes (e.g. role='tab' expects aria-selected on its parent context) ā check the ARIA specification or authoring guide when using a role to ensure all required properties are present.
Run eslint-plugin-jsx-a11y in CI to Catch Common ARIA Mistakes
Automated linting catches a meaningful share of invalid or missing ARIA before it ships, complementing (not replacing) manual screen reader testing.
Frequent Bugs
A custom widget with role='button' works visually but a screen reader announces confusing or contradictory information about it.
Check whether all required ARIA attributes for that role are present and correctly set ā an incomplete or mismatched ARIA implementation can actively confuse assistive technology rather than just being unhelpful.
aria-expanded={isOpen} seems to work, but a developer is confused why the DOM shows a string instead of a boolean.
This is expected ā ARIA attributes are HTML attributes, and HTML attributes are always strings. React converts the boolean to 'true'/'false' automatically when rendering to the DOM.
Real-World Examples
A Custom Combobox with Correct ARIA
A search-as-you-type combobox has no direct native HTML equivalent. Implementing it with role='combobox' on the input, aria-expanded reflecting whether the suggestion list is open, aria-controls pointing to the listbox's id, and role='option'/aria-selected on each suggestion gives screen reader users the same understanding of the widget's state that a native <select> would provide automatically.
<input
role="combobox"
aria-expanded={isOpen}
aria-controls="suggestions-listbox"
aria-activedescendant={activeId}
/>
<ul id="suggestions-listbox" role="listbox">
{suggestions.map(s => (
<li key={s.id} id={s.id} role="option" aria-selected={s.id === activeId}>{s.label}</li>
))}
</ul>