foundation
Native semantics before ARIA
Prefer native controls and only add ARIA when semantics or state cannot be expressed with HTML alone.
ARIA changes the accessibility tree but does not add browser behavior. A `button` beats `div role="button"` because it already supports focus, keyboard activation, disabled state, and form integration. Follow the first rule of ARIA: if a native element exists, use it.
Reach for ARIA for names, states, and relationships HTML cannot express — `aria-expanded`, `aria-controls`, `aria-invalid`, `aria-live` — and keep attributes synchronized with real UI state.
<!-- Prefer -->
<button type="button" aria-expanded="false" aria-controls="menu">Menu</button>
<!-- Avoid when native works -->
<div role="button" tabindex="0">Menu</div>
On interviews: first rule of ARIA, accessible name calculation, and common states.
Common pitfalls: wrong roles worse than no ARIA; `aria-label` hiding visible text carelessly.
The trade-off is faster div-based widgets versus native behavior — ARIA names state but does not recreate keyboard or form integration.
Checklist:
- Start with native HTML.
- Add ARIA only for missing semantics.
- Sync ARIA with component state.
- Verify in the accessibility tree.