Is there an existing issue for this?
What happened?
What happened?
Problem Statement
In ShareAlbumDialog.tsx, the share mode selector allows users to choose between "Local network" and "Internet" sharing. The selector buttons define role="radio" and aria-checked={mode === option.value}. However, the wrapping parent element is a standard div without role="radiogroup" or an accessible name (aria-label).
Under the WAI-ARIA 1.2 specification, elements with role="radio" require an enclosing role="radiogroup" parent container. Without this, assistive technologies (such as screen readers) treat each button as an isolated orphan radio button rather than a cohesive group of mutually exclusive options.
Context and Origin
The share dialog and mode selection were introduced in PR #1478 (feat: share an album beyond the local network, commit d1ccba1), building upon the album sharing feature in PR #1469 / PR #1473.
Root Cause Analysis
In frontend/src/components/Albums/ShareAlbumDialog.tsx (lines 479-498):
<div className="bg-muted grid w-full grid-cols-2 gap-1 rounded-lg p-1">
{MODE_OPTIONS.map((option) => (
<button
key={option.value}
type="button"
role="radio"
aria-checked={mode === option.value}
onClick={() => handleModeChange(option.value)}
className={cn(
'flex items-center justify-center gap-2 rounded-md px-3 py-2 text-sm font-medium transition-colors',
mode === option.value
? 'bg-background text-foreground shadow-sm'
: 'text-muted-foreground hover:text-foreground',
)}
>
<option.icon className="h-4 w-4" />
{option.label}
</button>
))}
</div>
The buttons declare role="radio", but the parent container <div className="bg-muted..."> does not declare role="radiogroup" or aria-label="Share mode".
In contrast, the "Keep sharing" section right below in the same file (line 518) correctly implements a radiogroup structure using the design system's <RadioGroup> component:
<RadioGroup value={expiry} onValueChange={setExpiry}>
Impact on Accessibility (WCAG 2.1 / WAI-ARIA)
- WAI-ARIA 1.2 Violation (
aria-required-parent): A radio role is semantically invalid unless contained within an element with role="radiogroup".
- Loss of Group Context: Screen readers (VoiceOver, NVDA, JAWS) do not announce the grouping label or position in group (e.g., "1 of 2", "2 of 2"). The user is not informed what setting these mutually exclusive choices configure.
- Automated Accessibility Audit Failure: Tools like axe-core, Lighthouse, and Accessibility Inspector flag
aria-required-parent errors on this container.
Visual Proof
Steps to Reproduce
- Open PictoPy.
- Navigate to Albums, open any album, and click the Share button to open
ShareAlbumDialog.
- Inspect the DOM structure of the "Local network" / "Internet" toggle button bar using DevTools or run an automated accessibility audit (axe / Lighthouse).
- Observe the
aria-required-parent error indicating role="radio" elements lack a parent with role="radiogroup".
Expected Behavior
The container element enclosing the mode selection buttons should specify role="radiogroup" and provide an explicit accessible label (aria-label="Share mode"), allowing screen readers to announce the grouping context and option indices.
Actual Behavior
The buttons are wrapped in a generic <div> with no accessibility role or label, causing the radio buttons to be announced as unlinked controls.
Proposed Solution
Add role="radiogroup" and an appropriate aria-label to the container div in frontend/src/components/Albums/ShareAlbumDialog.tsx:
<div
role="radiogroup"
aria-label="Share mode"
className="bg-muted grid w-full grid-cols-2 gap-1 rounded-lg p-1"
>
I have verified the issue and would like to submit a PR to resolve this if assigned.
Record
Is there an existing issue for this?
What happened?
What happened?
Problem Statement
In
ShareAlbumDialog.tsx, the share mode selector allows users to choose between "Local network" and "Internet" sharing. The selector buttons definerole="radio"andaria-checked={mode === option.value}. However, the wrapping parent element is a standarddivwithoutrole="radiogroup"or an accessible name (aria-label).Under the WAI-ARIA 1.2 specification, elements with
role="radio"require an enclosingrole="radiogroup"parent container. Without this, assistive technologies (such as screen readers) treat each button as an isolated orphan radio button rather than a cohesive group of mutually exclusive options.Context and Origin
The share dialog and mode selection were introduced in PR #1478 (
feat: share an album beyond the local network, commitd1ccba1), building upon the album sharing feature in PR #1469 / PR #1473.Root Cause Analysis
In
frontend/src/components/Albums/ShareAlbumDialog.tsx(lines 479-498):The buttons declare
role="radio", but the parent container<div className="bg-muted...">does not declarerole="radiogroup"oraria-label="Share mode".In contrast, the "Keep sharing" section right below in the same file (line 518) correctly implements a radiogroup structure using the design system's
<RadioGroup>component:Impact on Accessibility (WCAG 2.1 / WAI-ARIA)
aria-required-parent): Aradiorole is semantically invalid unless contained within an element withrole="radiogroup".aria-required-parenterrors on this container.Visual Proof
Steps to Reproduce
ShareAlbumDialog.aria-required-parenterror indicatingrole="radio"elements lack a parent withrole="radiogroup".Expected Behavior
The container element enclosing the mode selection buttons should specify
role="radiogroup"and provide an explicit accessible label (aria-label="Share mode"), allowing screen readers to announce the grouping context and option indices.Actual Behavior
The buttons are wrapped in a generic
<div>with no accessibility role or label, causing the radio buttons to be announced as unlinked controls.Proposed Solution
Add
role="radiogroup"and an appropriatearia-labelto the containerdivinfrontend/src/components/Albums/ShareAlbumDialog.tsx:I have verified the issue and would like to submit a PR to resolve this if assigned.
Record