Accessibility Issue: Form Inputs Without Associated Labels
WCAG Level: A
Severity: High
Category: Form Accessibility (WCAG 1.3.1, 4.1.2)
Issue Description
Multiple form inputs across the application lack properly associated <label> elements. While some inputs use placeholder text, this is insufficient for screen reader users and does not meet WCAG requirements for form accessibility.
User Impact
- Affected Users: Blind users, low vision users, cognitive disability users
- Severity: Users cannot understand the purpose of form fields when using screen readers
Violations Found
File: src/pages/Settings.tsx
Lines: 193-201, 241-248, 353-362
<!-- Current Code - Missing labels -->
<input
type="text"
placeholder="Strava Client ID"
value={stravaClientId}
onChange={(e) => setStravaClientId(e.target.value)}
style={{ ... }}
/>
<input
type="password"
placeholder="Strava Client Secret"
value={stravaSecret}
onChange={(e) => setStravaSecret(e.target.value)}
style={{ ... }}
/>
Issue: Inputs use placeholder as the only label, which disappears when user starts typing and is not announced properly by screen readers.
File: src/pages/WelcomeFlow.tsx
Lines: 137-148, 285-327
<!-- Current Code -->
<label>
<span className="start-date-label">Current weekly miles</span>
<input type="number" ... />
</label>
Issue: While these use implicit label association (wrapping), some inputs lack proper label text visibility for screen readers.
File: src/pages/Insights.tsx
Lines: 569-574
<!-- Current Code -->
<input type="number" value={hrMax} onChange={(e) => setHRMax(e.target.value)} ... />
<input type="number" value={hrResting} onChange={(e) => setHRResting(e.target.value)} ... />
Issue: HR max and resting inputs lack associated labels.
Recommended Fix
<!-- Fixed Code - Settings.tsx -->
<label htmlFor="strava-client-id" className="visually-hidden">Strava Client ID</label>
<input
id="strava-client-id"
type="text"
placeholder="Strava Client ID"
aria-label="Strava Client ID"
value={stravaClientId}
onChange={(e) => setStravaClientId(e.target.value)}
style={{ ... }}
/>
<!-- Or use visible labels (preferred) -->
<div className="form-field">
<label htmlFor="strava-client-id">Strava Client ID</label>
<input
id="strava-client-id"
type="text"
value={stravaClientId}
onChange={(e) => setStravaClientId(e.target.value)}
style={{ ... }}
/>
</div>
Changes Required:
- Add explicit
<label> elements with htmlFor attribute linking to input id
- Or add
aria-label attribute to inputs as a minimum fix
- Add visible labels where space permits (better UX)
- Ensure placeholder text is supplementary, not the only label
Additional Instances
src/pages/Settings.tsx - Garmin Client ID/Secret inputs (lines 241-248)
src/pages/Settings.tsx - Heart rate inputs (lines 353-362)
src/pages/Settings.tsx - Daily recap time input (line 294)
src/pages/Training.tsx - Date picker inputs
src/pages/Analytics.tsx - Period selector buttons (should have group label)
Testing Instructions
- Navigate to Settings page using keyboard only
- Use screen reader (NVDA/VoiceOver) to navigate form fields
- Verify each input announces its purpose
- Test with forms mode enabled in screen reader
Resources
Acceptance Criteria
Accessibility Issue: Form Inputs Without Associated Labels
WCAG Level: A
Severity: High
Category: Form Accessibility (WCAG 1.3.1, 4.1.2)
Issue Description
Multiple form inputs across the application lack properly associated
<label>elements. While some inputs use placeholder text, this is insufficient for screen reader users and does not meet WCAG requirements for form accessibility.User Impact
Violations Found
File:
src/pages/Settings.tsxLines: 193-201, 241-248, 353-362
Issue: Inputs use placeholder as the only label, which disappears when user starts typing and is not announced properly by screen readers.
File:
src/pages/WelcomeFlow.tsxLines: 137-148, 285-327
Issue: While these use implicit label association (wrapping), some inputs lack proper label text visibility for screen readers.
File:
src/pages/Insights.tsxLines: 569-574
Issue: HR max and resting inputs lack associated labels.
Recommended Fix
Changes Required:
<label>elements withhtmlForattribute linking to inputidaria-labelattribute to inputs as a minimum fixAdditional Instances
src/pages/Settings.tsx- Garmin Client ID/Secret inputs (lines 241-248)src/pages/Settings.tsx- Heart rate inputs (lines 353-362)src/pages/Settings.tsx- Daily recap time input (line 294)src/pages/Training.tsx- Date picker inputssrc/pages/Analytics.tsx- Period selector buttons (should have group label)Testing Instructions
Resources
Acceptance Criteria
htmlFor/idor implicit wrapping