Skip to content

[a11y][critical] HealthBar theme switcher: ToggleGroup type="single" lost radiogroup semantics #86

@fedorovvvv

Description

@fedorovvvv

Source: PRD-018 SC-2 audit, finding [Logic-C1].

template/src/widgets/health-bar/ui/HealthBar.svelte:93-106

The pre-migration theme switcher used role="radiogroup" with three role="radio" items (AUTO / LIGHT / DARK) carrying explicit aria-checked. After migration to <ToggleGroup type="single">, bits-ui renders these as a generic toggle group rather than a radio group. Screen readers will announce "toggle button group" instead of "radio group, 1 of 3 selected".

This is a silent a11y regression versus the pre-migration code.

Repro / Verification

  1. Run npm run dev in template/.
  2. Navigate to HealthBar's theme switcher.
  3. Inspect with Accessibility tab in Chrome DevTools — the radiogroup role should be present on the wrapper, radio on each item.

Fix options

  • (preferred) Wrap the ToggleGroup in role="radiogroup" + aria-label="Theme", then map each ToggleGroupItem to render with role="radio" aria-checked={...} when its parent is type="single". This requires a small extension of the shared/ui/toggle-group/ primitive (see RFC-016).
  • (workaround) Replace ToggleGroup here with three explicit Toggle primitives wired together as a manual radiogroup. Loses the bits-ui keyboard-navigation freebies.

Acceptance

  • DevTools Accessibility tree shows radiogroup on the wrapper and radio on each item.
  • Keyboard: arrow keys move selection, Tab exits the group (roving tabindex preserved).
  • VoiceOver / NVDA announce "radio button" for each option.

Audit traceability

  • Reviewer: Logic & Correctness, score 7/10
  • File: template/src/widgets/health-bar/ui/HealthBar.svelte

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:appbugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions