Skip to main content

accessibility-guide

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

Informações da origem

Repositório
SAP/fundamental-styles
Última atividade na origem
4 de junho de 2026 às 14:34
Idioma detectado do SKILL.md
inglês
Estrelas
235
Forks
73

Opções de instalação

Por padrão, está selecionado o prompt que primeiro revisa a origem. Você pode mudar para um comando direto ou baixar uma cópia local.

Revise os arquivos de origem

Leia o SKILL.md e os arquivos complementares exibidos pelo SkillsMP antes de decidir se vai instalar.

Exibindo SKILL.md

SKILL.md
Instruções da origem · Visualização somente leitura
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>
Ver no GitHub
Este SKILL.md e muito grande, entao o SkillsMP mostra aqui apenas a primeira secao. Ver no GitHub