Accessibility không phải tính năng thêm, mà là cách build mặc định.
- Semantic HTML trước tiên: dùng
<button>,<nav>,<main>,<label>thay vì<div onClick>. Native element có sẵn role, keyboard handling, focus — ARIA chỉ để vá khi không có element phù hợp. "No ARIA is better than bad ARIA." - ARIA khi cần:
aria-label,aria-expanded,role="dialog",aria-livecho nội dung động (toast, validation). ARIA chỉ đổi cách screen reader đọc, không thêm hành vi. - Focus management: khi mở modal phải move focus vào trong và trap nó; khi đóng phải trả focus về trigger. Route change nên focus heading. Đừng để focus rơi vào
<body>. - useId cho label: tạo id ổn định, duy nhất, khớp giữa server và client (SSR) để nối
<label htmlFor>với<input id>hayaria-describedby. Đừng dùng cho key trong list.
tsx
function Field({ label }) {
const id = useId()
return (
<>
<label htmlFor={id}>{label}</label>
<input id={id} aria-describedby={`${id}-hint`} />
<p id={`${id}-hint`}>Hint text</p>
</>
)
}