Skip to content

fix(a11y): accessibility issues - #6437

Open
akinshaywai wants to merge 4 commits into
heroui-inc:v3from
akinshaywai:fix/checkbox-nested-label-aria
Open

fix(a11y): accessibility issues#6437
akinshaywai wants to merge 4 commits into
heroui-inc:v3from
akinshaywai:fix/checkbox-nested-label-aria

Conversation

@akinshaywai

Copy link
Copy Markdown

Summary

Three accessibility fixes across components and documentation demos.


Fix 1 — Checkbox: prevent nested <label> elements (#6434)

Problem: CheckboxPrimitive (from react-aria-components) renders a <label> as its root. When a <Label> component is placed inside Checkbox.Content, the DOM contains a <label> nested inside another <label> — invalid HTML per spec and confusing for assistive technology.

Fix: Provide LabelContext with { elementType: 'span' } inside CheckboxRoot so any <Label> inside the Checkbox tree renders as <span> rather than <label>.


Fix 2 — Switch: same nested <label> fix

SwitchPrimitive has the same root-<label> pattern. Applied the identical LabelContext override inside SwitchRoot.


Fix 3 — Docs: add aria-label to icon-only buttons (WCAG 4.1.2) (#6427)

Icon-only buttons in several demos were missing accessible names, causing screen readers to announce only "button" with no context — a WCAG 2.1 SC 4.1.2 violation.

Fixed in:

  • table/custom-cells.tsx — copy-ID, view, edit, delete buttons now have contextual labels (e.g., "View Jane Doe", "Delete Jane Doe")
  • tooltip/basic.tsxaria-label="More information" on icon-only trigger
  • popover/with-arrow.tsxaria-label="More options" on icon-only trigger

Icon-only buttons in the Button and ButtonGroup demos had no
accessible names, so screen readers announced them as plain
"button" with no context. Developers copy these examples directly,
so they should demonstrate the correct accessible pattern.

- button/icon-only: More options, Settings, Delete
- button-group/with-icons: Search, Add, Delete

Fixes WCAG 2.1 SC 4.1.2 (Name, Role, Value).
CheckboxPrimitive (react-aria-components) renders a <label> as its root
element. When a <Label> component is placed inside Checkbox.Content, the
DOM contains a <label> descending from another <label>, which the HTML
spec explicitly prohibits and which confuses assistive technology.

Provide LabelContext with { elementType: 'span' } inside CheckboxRoot so
that any Label rendered within the Checkbox tree renders as a <span>
instead of a <label>, maintaining correct accessible naming while
producing valid HTML.

Fixes heroui-inc#6434
SwitchPrimitive (react-aria-components) renders a <label> as its root.
Same nested-label issue as Checkbox (heroui-inc#6434): placing a <Label> inside
Switch produces invalid HTML and AT confusion.

Provide LabelContext with { elementType: 'span' } inside SwitchRoot so
labels render as <span> elements within the Switch tree.

Part of heroui-inc#6434
Icon-only buttons in several documentation demos were missing accessible
names, causing screen readers to announce only 'button' with no context.
This violates WCAG 2.1 SC 4.1.2 Name, Role, Value.

- table/custom-cells: add contextual aria-labels to copy-ID, view, edit
  and delete buttons that include the row entity (user name / ID)
- tooltip/basic: add aria-label='More information' to icon-only trigger
- popover/with-arrow: add aria-label='More options' to icon-only trigger

Fixes heroui-inc#6427
@vercel

vercel Bot commented Apr 17, 2026

Copy link
Copy Markdown

@akinshaywai is attempting to deploy a commit to the HeroUI Inc Team on Vercel.

A member of the Team first needs to authorize it.

@wingkwong wingkwong changed the title fix(a11y): prevent nested <label> in Checkbox/Switch + add aria-labels to icon-only buttons fix(a11y): accessibility issues Apr 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant