Skip to main content

accessibility-guide

Accessibility guidelines for writing component examples in fundamental-styles with proper ARIA, semantic HTML, and WCAG compliance

معلومات المصدر

المستودع
SAP/fundamental-styles
آخر نشاط في المصدر
٤ يونيو ٢٠٢٦ في ١٤:٣٤
لغة SKILL.md المكتشفة
الإنجليزية
النجوم
٢٣٥
التفرعات
٧٣

خيارات التثبيت

يُحدَّد Prompt الذي يراجع المصدر أولًا بشكل افتراضي. يمكنك التبديل إلى أمر مباشر أو تنزيل نسخة محلية.

مراجعة ملفات المصدر

اقرأ SKILL.md وأي ملفات مرافقة يعرضها SkillsMP قبل أن تقرر التثبيت.

عرض SKILL.md

SKILL.md
تعليمات المصدر · معاينة للقراءة فقط
name
accessibility-guide
description
Accessibility guidelines for writing component examples in fundamental-styles with proper ARIA, semantic HTML, and WCAG compliance
# Accessibility Guide for fundamental-styles **When to use this skill:** - Writing HTML examples for component documentation - Creating new component demos - Reviewing component accessibility - Fixing accessibility issues in examples - Questions about ARIA roles and attributes ## Core Principles ### 1. Semantic HTML First Always prefer native HTML elements over ARIA roles when possible. ✅ **DO:** ```html <button>Click me</button> <nav>...</nav> <header>...</header> <input type="checkbox" /> ``` ❌ **DON'T:** ```html <div role="button">Click me</div> <div role="navigation">...</div> <div role="banner">...</div> <div role="checkbox"></div> ``` **Why:** Native elements provide built-in keyboard support, focus management, and semantics without JavaScript. ### 2. Labels MUST Be Properly Connected Every form control must have an accessible label. ✅ **DO - Use `for` and `id`:** ```html <label for="username">Username:</label> <input id="username" type="text" name="username" /> ``` ✅ **DO - Nested label (alternative):** ```html <label> Username: <input type="text" name="username" /> </label> ``` ✅ **DO - Using `aria-labelledby` for complex labels:** ```html <span id="label-firstname">First Name</span> <span id="label-required">(required)</span> <input type="text" aria-labelledby="label-firstname label-required" /> ``` ❌ **DON'T - Missing connection:** ```html <label>Username</label> <input type="text" /> <!-- No for/id connection --> ``` ❌ **DON'T - Non-existent ID reference:** ```html <label for="nonexistent">Username</label> <input id="username" type="text" /> <!-- Mismatched IDs --> ``` ### 3. ID References Must Be Valid When using `aria-labelledby`, `aria-describedby`, or `for` attributes, the referenced IDs **must exist in the DOM**. ✅ **DO:** ```html <h2 id="dialog-title">Confirm Action</h2> <div role="dialog" aria-labelledby="dialog-title" aria-describedby="dialog-desc"> <p id="dialog-desc">Are you sure you want to proceed?</p> <button>Confirm</button> </div> ``` ❌ **DON'T:** ```html <div role="dialog" aria-labelledby="missing-title"> <!-- ID 'missing-title' doesn't exist --> </div> ``` **Validation checklist:** - [ ] Every `for` attribute points to an existing `id` - [ ] Every `aria-labelledby` references existing ID(s) - [ ] Every `aria-describedby` references existing ID(s) - [ ] Every `aria-controls` references existing ID(s) - [ ] IDs are unique within the page ## ARIA Role Requirements ### Roles That Require Companion Attributes Some ARIA roles **only work when paired with specific attributes**. Missing these makes the component inaccessible. #### 1. Range Widgets (slider, spinbutton, progressbar, scrollbar) **MUST include:** - `aria-valuenow` - Current value - `aria-valuemin` - Minimum value - `aria-valuemax` - Maximum value ✅ **DO:** ```html <div role="slider" aria-valuenow="50" aria-valuemin="0" aria-valuemax="100" aria-label="Volume" tabindex="0"></div> <div role="progressbar" aria-valuenow="60" aria-valuemin="0" aria-valuemax="100" aria-label="Upload progress">60%</div> ``` ❌ **DON'T:** ```html <div role="slider" aria-label="Volume" tabindex="0"></div> <!-- Missing aria-valuenow, aria-valuemin, aria-valuemax --> ``` **Optional but recommended:** - `aria-valuetext` - Human-readable value (e.g., "Small", "50%", "$1,000") #### 2. Checked/Selectable Widgets (checkbox, radio, switch, option, menuitemcheckbox, menuitemradio, tab) **MUST include:** - `aria-checked` for checkbox, radio, switch, menuitemcheckbox, menuitemradio - `aria-selected` for option, tab ✅ **DO:** ```html <div role="checkbox" aria-checked="false" aria-label="Subscribe to newsletter" tabindex="0"></div> <button role="tab" aria-selected="true" aria-controls="panel-1" id="tab-1">Tab 1</button> <div role="option" aria-selected="false">Option 1</div> ``` ❌ **DON'T:** ```html <div role="checkbox" aria-label="Subscribe" tabindex="0"></div> <!-- Missing aria-checked --> <button role="tab">Tab 1</button> <!-- Missing aria-selected --> ``` #### 3. Expandable Widgets (combobox, disclosure, menu with submenus) **MUST include:** - `aria-expanded` - "true" when expanded, "false" when collapsed ✅ **DO:** ```html <button aria-expanded="false" aria-controls="submenu-1">File Menu</button> <ul id="submenu-1" hidden> <li>New</li> <li>Open</li> </ul> <div role="combobox" aria-expanded="false" aria-haspopup="listbox" aria-owns="listbox-1"> <input type="text" /> <ul role="listbox" id="listbox-1" hidden> ... </ul> </div> ``` ❌ **DON'T:** ```html <button aria-controls="submenu-1">File Menu</button> <!-- Missing aria-expanded --> ``` #### 4. Popup Triggers (combobox, menu button) **MUST include:** - `aria-haspopup` - Type of popup ("menu", "listbox", "tree", "grid", "dialog", or "true") ✅ **DO:** ```html <button aria-haspopup="menu" aria-expanded="false">Options</button> <div role="combobox" aria-haspopup="listbox" aria-expanded="false"> <input type="text" /> </div> ``` #### 5. Set Position Attributes (aria-posinset, aria-setsize) **These MUST be used together** when not all items are present in the DOM (e.g., virtual scrolling, lazy loading). ✅ **DO:** ```html <!-- Showing items 1, 3, 11, 19 out of 118 total --> <ul role="listbox"> <li role="option" aria-setsize="118" aria-posinset="1">Item 1</li> <li role="option" aria-setsize="118" aria-posinset="3">Item 3</li> <li role="option" aria-setsize="118" aria-posinset="11">Item 11</li> <li role="option" aria-setsize="118" aria-posinset="19">Item 19</li> </ul> ``` ❌ **DON'T:** ```html <li role="option" aria-posinset="3">Item 3</li> <!-- Missing aria-setsize --> ``` **When to omit:** - When all items are in the DOM (browser can calculate automatically) - Set `aria-setsize="-1"` if total size is unknown #### 6. Set Orientation (menu, menubar, toolbar, listbox, slider, tablist, tree) Some roles have implicit orientation. Override when needed. **Defaults:** - `menu` → implicit `aria-orientation="vertical"` - `menubar` → implicit `aria-orientation="horizontal"` - `slider` → implicit `aria-orientation="horizontal"` - `tablist` → implicit `aria-orientation="horizontal"` ✅ **DO - Override when different from default:** ```html <!-- Horizontal menu needs explicit orientation --> <div role="menu" aria-orientation="horizontal"> <button role="menuitem">File</button> <button role="menuitem">Edit</button> </div> <!-- Vertical tabs need explicit orientation --> <div role="tablist" aria-orientation="vertical"> <button role="tab">Tab 1</button> <button role="tab">Tab 2</button> </div> ``` #### 7. Modal Dialogs **MUST include:** - `aria-modal="true"` (or `aria-modal="false"` for non-modal) - `aria-labelledby` OR `aria-label` to name the dialog ✅ **DO:** ```html <div role="dialog" aria-modal="true" aria-labelledby="dialog-title"> <h2 id="dialog-title">Confirm Delete</h2> <p>Are you sure?</p> <button>Cancel</button> <button>Delete</button> </div> ``` ❌ **DON'T:** ```html <div role="dialog"> <h2>Confirm Delete</h2> <!-- Missing aria-modal and aria-labelledby --> </div> ``` ### Composite Widgets - Container Requirements Some roles **require specific child roles** to be valid. #### 1. Radio Groups `radiogroup` MUST contain `radio` elements. ✅ **DO:** ```html <div role="radiogroup" aria-labelledby="group-label"> <span id="group-label">Select size:</span> <div role="radio" aria-checked="false" tabindex="0">Small</div> <div role="radio" aria-checked="true" tabindex="0">Medium</div> <div role="radio" aria-checked="false" tabindex="0">Large</div> </div> ``` ❌ **DON'T:** ```html <!-- Isolated radio without radiogroup --> <div role="radio" aria-checked="false">Small</div> <div role="radio" aria-checked="false">Medium</div> ``` **Rules:** - Only ONE radio can have `aria-checked="true"` within a radiogroup - All radios in group must have `tabindex` (typically only checked one has `tabindex="0"`) #### 2. Tab Interface `tablist` MUST contain `tab` elements. Each `tab` should control a `tabpanel`. ✅ **DO:** ```html <div role="tablist" aria-label="Product categories"> <button role="tab" aria-selected="true" aria-controls="panel-1" id="tab-1" tabindex="0">Electronics</button> <button role="tab" aria-selected="false" aria-controls="panel-2" id="tab-2" tabindex="-1">Clothing</button> </div>
عرض على GitHub
ملف SKILL.md هذا كبير جدا، لذلك يعرض SkillsMP القسم الاول فقط هنا. عرض على GitHub