Nền tảng
Tiêu điểm và bàn phím
Đã đặc tảMọi luồng đi được bằng bàn phím. Ring tiêu điểm là --nf-semantic-focus-ring, dày --nf-component-focus-width (3px), lệch --nf-component-focus-offset (2px). Tiêu điểm không bao giờ bị che. Overlay trả tiêu điểm về nơi nó đến.
Nghĩa vụ
Obligation
Thông tin
Quan sát sáng 2026-09-23: apps/nexoframe khi đó không có phần tử <main>và không có skip link — hai vi phạm A18 và A28 trên chính site công bố luật trợ năng. Cả hai đã được sửa trong cùng đợt nâng cấp mở trang này.
A16
A16 Ring nhìn thấy được
:focus-visible, không phải :focus. Ring dày 3px, lệch 2px, màu --nf-semantic-focus-ring. Không dùng outline: none trừ khi cùng lúc vẽ một chỉ báo khác rõ ràng bằng hoặc hơn. Ring là một hình, không phải một sắc độ.
Kiểm. Tab qua mọi điều khiển trên trang. Mỗi bước dừng phải thấy được ring mà không cần tìm. Bấm chuột vào cùng những điều khiển đó: ring không được hiện.
A17
A17 Tiêu điểm không bị che
Khi một phần tử nhận tiêu điểm, nó phải nhìn thấy được — không nằm dưới header dính, không nằm sau drawer, không bị cuộn ra ngoài vùng nhìn. scroll-margin-top bằng chiều cao header là cách sửa.
Kiểm. Tab tới điều khiển đầu tiên nằm dưới mép cuộn. Nó phải hiện đầy đủ, không bị cắt ở mép trên.
A18
A18 Bỏ qua khối lặp
Liên kết đầu tiên trong thứ tự tab là "Bỏ qua tới nội dung", trỏ tới id của main. Nó ẩn cho tới khi nhận tiêu điểm, rồi hiện rõ. Landmark là điều kiện đi kèm, không phải thay thế: <header>, <nav> có nhãn, <main> mỗi trang đúng một lần.
A19
A19 Thứ tự và bẫy
Thứ tự tab theo thứ tự đọc trực quan. Không dùng tabindex dương. Dialog và Sheet modal giữ tiêu điểm bên trong khi đang mở — đó là hành vi đúng, không phải bẫy — miễn là Escape luôn đóng được. Popover không modal không giữ tiêu điểm.
A20
A20 Trả tiêu điểm
Đóng overlay thì tiêu điểm về đúng điều khiển đã mở nó. Nếu điều khiển đó đã biến mất, tiêu điểm về phần tử ổn định gần nhất, và trang phải thông báo điều gì vừa xảy ra qua vùng aria-live. Radix làm sẵn phần lớn việc này cho Dialog, Sheet, Popover, Select — đừng ghi đè onCloseAutoFocus trừ khi có lý do viết ra được.
Hợp đồng
Bàn phím: hợp đồng tối thiểu của một điều khiển
| Điều khiển | Phím phải hoạt động |
|---|---|
| Button | EnterSpace |
| Link (kể cả Button asChild trên <a>) | Enter |
| Input, Textarea | GõEnter gửi |
| Select | Enter/Space mởmũi tênEnter chọnEscape đóng |
| Dialog, Sheet | Escape đóng |
| Popover | Escape đóng |
Cảnh báo
Đừng bắt một phím tắt một-ký-tự không có bổ trợ khi tiêu điểm đang ở trong ô nhập. Đừng dùng <div onClick> cho một hành động — đó là nguyên tắc P3.
Render
Tab qua các điều khiển thật
Ba điều khiển thật, không mô tả: Tab qua chúng để thấy ring của chính hệ thống.
Chưa quyết
Open questions
| Question | Owner | Resolves when |
|---|---|---|
| Site có công bố bảng phím tắt toàn cục không? | nexoboxvn@gmail.com | ⌘K và ⌘B đã tồn tại nhưng chưa được đặc tả ở đâu trong corpus này |
| Roving tabindex cho nhóm nút có được đặc tả không? | nexoboxvn@gmail.com | Một primitive nhóm (Tabs, Toolbar, RadioGroup) có file trong 03_components/ |