Skip to content

Accessibility baseline: aria attributes, roles, and semantic HTML #673

@ravisuhag

Description

@ravisuhag

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., menuitem inside menu)

Metadata

Metadata

Assignees

No one assigned

    Labels

    globalCross-cutting issue affecting multiple componentstriage

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions