feat(v2): audio history player is keyboard-inaccessible despite declaring role="slider"
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 25/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Stale
- Tech stack
- react, typescript
- Domain
- accessibility, frontend
Research direction
Start in desktop/src/components/AudioPlayer.tsx, at the div with role="slider" that handles the waveform seek click, and check the disabled={!peaks} guard on the Play button. Keyboard support needs focus, the arrow/Home/End/Space keys, and aria-valuetext. A linked pull request (#185) is already open, so check it before starting. Done means Tab reaches the seeker after audio loads and the keys seek as the issue lists.
Written by the indexing model from the issue text.
Description
What happened?
The waveform seeker in the audio history player (desktop/src/components/AudioPlayer.tsx) declares role="slider" with the correct ARIA attributes (aria-valuemin, aria-valuemax, aria-valuenow), but the element has no tabIndex and no onKeyDown handler:
<div
role="slider"
aria-label="Playback position"
aria-valuemin={0}
aria-valuemax={Math.round(duration)}
aria-valuenow={Math.round(time)}
onClick={...}
className="flex h-10 flex-1 items-center gap-[2px]"
>
- No tabIndex: The seeker is unreachable via Tab navigation.
- No onKeyDown: Arrow keys, Space, Home, and End do nothing even if the element is focused.
- No aria-valuetext: Screen readers announce a raw integer (e.g. "32") instead of a human-readable position (e.g. "0:32 of 1:45").
- The Play/Pause button is correctly reachable by keyboard, so a keyboard-only user can start playback but cannot seek at all.
Expected Behaviour
Per the W3C ARIA slider keyboard contract:
| Key | Action |
|---|---|
← |
Seek back 5 seconds |
→ |
Seek forward 5 seconds |
Home |
Jump to start |
End |
Jump to end of clip |
Space / Enter |
Toggle play/pause |
The seeker should also be reachable via Tab once audio has loaded, and show a focus ring consistent with other interactive elements in the app.
Proposed Solution
- Add tabIndex={0} (guarded: only after audio loads, i.e. when peaks is set, matching the existing disabled={!peaks} guard on the Play button).
- Add an onKeyDown handler implementing the ARIA slider keyboard pattern above.
- Add aria-valuetext to expose "0:32 of 1:45" to screen readers.
- Add focus-visible:ring-2 focus-visible:ring-accent/50 for the keyboard focus ring, consistent with the accent colour already used for the filled portion of the waveform.
All changes are confined to AudioPlayer.tsx. No new dependencies. No existing mouse/click behaviour changes.
I would be happy to submit a pull request for this.
Steps to reproduce
1. Open SpeakType and go to the History screen.
2. Select any transcription with recorded audio.
3. Try navigating to the waveform progress slider using the Tab key.
4. Notice that focus skips the waveform entirely, and arrow keys cannot seek playback.
### Which system?
Windows
### System version
Windows 11
### SpeakType version
2.0.0
### Which model were you using?
_No response_
### Anything else?
### Proposed Solution
1. Add `tabIndex={0}` guarded by `peaks` (matching the existing `disabled={!peaks}` guard on the Play button).
2. Add an `onKeyDown` handler implementing the ARIA slider keyboard pattern (`ArrowLeft`/`ArrowRight` ±5s, `Home`/`End`, `Space`/`Enter`).
3. Add `aria-valuetext` to expose `"0:32 of 1:45"` to screen readers via `formatClock`.
4. Add `focus-visible:ring-2 focus-visible:ring-accent/50` for the focus ring.
All changes are confined to [`AudioPlayer.tsx`](file:/speaktype/desktop/src/components/AudioPlayer.tsx). No new dependencies. Existing mouse click seeking is untouched.
I already have this tested and working on submitting it in a PR.
- Dominant language
- Swift
- Stars
- 540
- Forks
- 74
- PR merge metrics
- No merged PRs in 30d
Getting set up
- No Dockerfile or Docker Compose file
- No pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from karansinghgit/speaktype
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 67/100
karansinghgit/speaktype#211 ·
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 66/100
karansinghgit/speaktype#183 · 1 comment ·
-
enhancement
Difficulty 5/5 Over a week Newbie friendliness 35/100
karansinghgit/speaktype#209 ·
-
enhancement
Difficulty 5/5 Over a week Newbie friendliness 25/100
karansinghgit/speaktype#208 · 2 comments ·
-
bug
Difficulty 3/5 1-2 days Newbie friendliness 52/100
karansinghgit/speaktype#207 ·
All issues in karansinghgit/speaktype
Similar issues
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
vorssaint/vorssaint-utils#3917 ·
Maintainers usually reply within 2 days
-
Difficulty 2/5 1-3 hours Newbie friendliness 74/100
swiftlang/swift-markdown#299 ·
-
send.tracked never delivers to SMS or RCS chats: lowercased GUIDs stay unsent with error 4Possibly taken @thurstonsand claimed this today. Openclawsweeper:linked-pr-open clawsweeper:needs-live-repro clawsweeper:no-new-fix-pr impact:message-loss issue-rating: 🐚 platinum hermit P1
Difficulty 2/5 1-3 hours Newbie friendliness 74/100
openclaw/imsg#390 · 1 comment · 1 reaction ·
Maintainers usually reply within 1 day
-
area: agents follow-up
Difficulty 2/5 1-3 hours Newbie friendliness 77/100
manaflow-ai/cmux#37234 · 1 comment ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
thunderbird/thunderbird-ios#628 ·
Maintainers usually reply within 1 day