-
Notifications
You must be signed in to change notification settings - Fork 13
Description
Summary
Multiple components have accessibility gaps around ARIA attributes, role semantics, and HTML structure. This issue consolidates all cross-component accessibility fixes that follow a common pattern.
Goal
Ensure all components meet WCAG 2.1 AA baseline for ARIA usage, role semantics, and semantic HTML structure.
Affected Components
| Component | Details |
|---|---|
| Tooltip (#648) | No accessible label for ReactNode messages; trigger wrapper lacks semantics |
| Toast (#647) | Sonner accessibility not verified or documented |
| TextArea (#645) | Missing htmlFor/id association, aria-invalid, aria-describedby |
| Tabs (#643) | No aria-hidden on decorative leadingIcon |
| Table (#642) | Missing scope on <th>, no <caption>, no aria-sort |
| Spinner (#640) | aria-hidden="true" conflicts with role="status"; no ariaLabel prop |
| Slider (#639) | No aria-label on root; missing getAriaValueText callback |
| Skeleton (#638) | Missing aria-hidden="true" on decorative placeholder |
| Sidebar (#637) | role="menuitem" outside role="menu" container; hidden text uses display: none instead of sr-only |
| SidePanel (#636) | No semantic heading in header; no aria-labelledby on <aside> |
| Sheet (#635) | aria-label='Sheet' hardcoded, not customizable |
| Separator (#634) | No decorative variant (role="presentation" / aria-hidden) |
| Select (#633) | role="dialog" conflicts with aria-multiselectable; onBlurCapture prevents AT blur |
| ScrollArea (#631) | No aria-label/aria-labelledby on scrollable region |
| List (#626) | Redundant role="list"/role="listitem" on native elements; hardcoded aria-level; generic default aria-label |
| Link (#625) | ${children} produces "[object Object]" in aria-label; redundant role="link" |
| Label (#624) | Required indicator hidden from screen readers with no "(required)" text; redundant aria-hidden + role="presentation" |
| InputField (#623) | Missing htmlFor, aria-describedby, icon accessible name |
| Image (#621) | Redundant accessibility attributes |
| IconButton (#620) | Redundant aria-disabled; aria-label should be required |
| Container (#610) | Default role="region" may not be appropriate |
| Chip (#605) | Non-standard ariaLabel prop (should be aria-label) |
| Button (#601) | Missing aria-busy when loading |
| Breadcrumb (#600) | No default aria-label on <nav>; separators lack role="presentation"; missing aria-current="page" |
| AnnouncementBar (#596) | Action uses <Text onClick> instead of <button> — not keyboard accessible |
Common Patterns to Fix
1. Label-input association
Components with labels must use htmlFor/id to associate label with control.
Affected: TextArea, InputField
2. aria-describedby for helper/error text
Error messages and helper text must be linked via aria-describedby.
Affected: TextArea, InputField
3. Redundant ARIA on native elements
Native elements already have implicit roles — remove explicit duplicates.
Affected: Link (role="link"), List (role="list"/role="listitem"), IconButton (aria-disabled), Label, Image
4. Decorative content needs aria-hidden
Icons, separators, and loading placeholders should be hidden from AT.
Affected: Tabs (leadingIcon), Skeleton, Separator
5. Accessible labels for interactive elements
Icon-only buttons, non-text content must have accessible names.
Affected: IconButton, Spinner, Slider, Chip
6. Semantic HTML structure
Use proper HTML elements instead of generic divs with ARIA roles.
Affected: SidePanel (heading), Breadcrumb (separators in <ol>), AnnouncementBar (action button)
Acceptance Criteria
- All form controls have proper label association
- Error/helper text linked via
aria-describedby - No redundant ARIA attributes on native elements
- Decorative content has
aria-hidden="true" - All interactive elements have accessible names
- ARIA roles follow proper hierarchy (e.g.,
menuiteminsidemenu)