Skip to content

fix(video-player): accessibility & controls-visibility UX for NetflixStylePlayer (#1333)#1374

Merged
rohan-pandeyy merged 5 commits into
AOSSIE-Org:mainfrom
VanshajPoonia:fix/1333-netflix-player-a11y
Jul 19, 2026
Merged

fix(video-player): accessibility & controls-visibility UX for NetflixStylePlayer (#1333)#1374
rohan-pandeyy merged 5 commits into
AOSSIE-Org:mainfrom
VanshajPoonia:fix/1333-netflix-player-a11y

Conversation

@VanshajPoonia

@VanshajPoonia VanshajPoonia commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

Addressed Issues

Fixes #1333 (follow-up to #1329 / #1339 in the same component).

What this does

Builds on the merged #1339 desync fixes to close the remaining accessibility and UX gaps in NetflixStylePlayer:

  1. Title / description rendered — shown as an overlay that fades in/out with the controls. It's pointer-events-none, so it never steals clicks from the play/pause area beneath it.
  2. Accessible progress bar — exposed as a slider: role="slider", aria-valuemin/max/now, aria-valuetext, focusable (tabIndex=0), and seekable via ←/→ (±5s) and Home/End. Stops event propagation so the seek-bar keys don't also fire the global ±10s shortcut.
  3. Control-button aria-labels — descriptive, state-aware labels on rewind, play/pause, fast-forward, mute, volume slider, and fullscreen (folded into this issue's scope per the thread). aria-label is forwarded through the shared Slider onto the Radix Thumb.
  4. Controls-visibility UX — visible by default while paused (Netflix-style), auto-hide after a short delay and on mouse-leave while playing, and reveal on touch and keyboard focus. Hidden controls are non-interactive (pointer-events-none) rather than merely transparent.

Screenshots / Recordings

No layout/styling changes to the existing controls. New user-visible behavior:

  • Title & description overlay appears at the top and fades with the controls.
  • Progress bar is now keyboard-focusable and operable by assistive tech.
  • Controls stay visible while paused and auto-hide while playing.

Testing

  • Added regression tests covering the title/description overlay, seek-bar accessibility + keyboard seeking, control aria-labels, and the paused/playing visibility logic.
  • Full frontend suite: 154/154 passing (19 suites).
  • tsc --noEmit, eslint, and vite build all clean.

AI Usage Disclosure

  • This PR contains AI-generated code. I have read the AI Usage Policy and this PR complies with it. I have tested the code locally and I am responsible for it.

Tool used: Claude Code (Claude Opus 4.8).

Checklist

  • My PR addresses a single issue, fixes a single bug or makes a single improvement.
  • My code follows the project's code style and conventions
  • If applicable, I have made corresponding changes or additions to the documentation
  • If applicable, I have made corresponding changes or additions to tests
  • My changes generate no new warnings or errors
  • I have read the Contribution Guidelines

Summary by CodeRabbit

  • New Features

    • Added Netflix-style video overlays with configurable titles and descriptions.
    • Updated player controls to reveal temporarily on interaction and automatically hide while playing.
    • Enhanced keyboard support for the seek bar (Arrow, Home, End).
  • Bug Fixes

    • Improved control visibility and interaction behavior across mouse and keyboard use.
    • Strengthened accessibility by adding descriptive aria-labels for player controls and the seek/progress slider.

@github-actions github-actions Bot added bug Something isn't working frontend labels Jul 11, 2026
@coderabbitai

coderabbitai Bot commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 438920bf-7468-4506-baf3-19b2e4d56124

📥 Commits

Reviewing files that changed from the base of the PR and between ac752e9 and 9dd7523.

📒 Files selected for processing (2)
  • frontend/src/components/VideoPlayer/NetflixStylePlayer.tsx
  • frontend/src/components/VideoPlayer/__tests__/NetflixStylePlayer.test.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • frontend/src/components/VideoPlayer/tests/NetflixStylePlayer.test.tsx
  • frontend/src/components/VideoPlayer/NetflixStylePlayer.tsx

Walkthrough

NetflixStylePlayer now supports metadata overlays, timed control visibility, keyboard seeking, and expanded accessibility labels. Tests cover the new overlay, seek-bar behavior, control labels, and visibility states. Slider forwards an accessible label to its thumb.

Changes

Netflix-style player accessibility

Layer / File(s) Summary
Control visibility and keyboard input
frontend/src/components/VideoPlayer/NetflixStylePlayer.tsx
Control timing, keyboard shortcuts, pointer interactions, and seek-bar navigation use shared reveal and hide behavior.
Player presentation and accessibility
frontend/src/components/VideoPlayer/NetflixStylePlayer.tsx, frontend/src/components/ui/Slider.tsx
Title and description overlays are rendered, controls toggle visibility and pointer interaction, and player controls and slider thumbs receive accessible labels.
Player behavior coverage
frontend/src/components/VideoPlayer/__tests__/NetflixStylePlayer.test.tsx
Tests validate metadata rendering, keyboard seeking, state-aware labels, and control visibility transitions.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Viewer
  participant NetflixStylePlayer
  participant VideoElement
  Viewer->>NetflixStylePlayer: Enter player or press control key
  NetflixStylePlayer->>VideoElement: Play, seek, mute, or fullscreen action
  NetflixStylePlayer-->>Viewer: Show controls and metadata
  NetflixStylePlayer-->>Viewer: Hide controls after timeout
Loading

Possibly related issues

  • AOSSIE-Org/PictoPy issue 1333 — Directly covers the title/description overlay, accessible seek bar, labeled controls, and control-visibility behavior implemented here.

Suggested labels: TypeScript/JavaScript

Suggested reviewers: rohan-pandeyy

Poem

I’m a rabbit with buttons that fade,
A seek bar hops where arrows are laid.
Titles bloom bright, then softly hide,
Labels guide each control’s stride.
Hop, play, pause—the player’s wide! 🐇

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main changes: accessibility improvements and controls visibility UX updates for NetflixStylePlayer.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

…tflixStylePlayer (AOSSIE-Org#1333)

Follow-up to AOSSIE-Org#1329/AOSSIE-Org#1339 in the same component. Addresses the remaining
accessibility and UX gaps:

- Render title/description as an overlay that fades with the controls.
  It is non-interactive (pointer-events-none) so it never steals clicks
  from the play/pause area beneath it.
- Expose the progress bar as an accessible slider: role="slider",
  aria-valuemin/max/now, aria-valuetext, focusable, seekable via
  Left/Right (+/-5s) and Home/End. Stops event propagation so the
  seek-bar keys don't also trigger the global +/-10s shortcut.
- Add descriptive, state-aware aria-labels to every control button and
  the volume slider (play/pause, mute, fullscreen toggles). Forward
  aria-label through the shared Slider onto the Radix Thumb.
- Rework controls-visibility: visible by default while paused
  (Netflix-style), auto-hide after a delay and on mouse-leave while
  playing, reveal on touch and keyboard focus. Hidden controls are
  non-interactive (pointer-events-none).

Adds regression tests for the title/description overlay, seek-bar
accessibility and keyboard seeking, control aria-labels, and the
paused/playing visibility logic.
@VanshajPoonia
VanshajPoonia force-pushed the fix/1333-netflix-player-a11y branch from a4d7a66 to ac752e9 Compare July 11, 2026 06:51

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
frontend/src/components/VideoPlayer/NetflixStylePlayer.tsx (1)

66-104: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Ignore global shortcuts while an interactive control is focused.

Pressing Space on a focused control reaches this document listener and also triggers the control’s native activation. For example, Space on Play can toggle playback twice, while Space on Mute unexpectedly toggles playback.

Proposed fix
     const handleKeyDown = (e: KeyboardEvent) => {
       const activeEl = document.activeElement;
       if (
-        activeEl &&
-        (activeEl.tagName === 'INPUT' ||
-          activeEl.tagName === 'TEXTAREA' ||
-          activeEl.getAttribute('contenteditable') === 'true')
+        activeEl instanceof HTMLElement &&
+        activeEl.closest(
+          'button, input, textarea, select, a[href], [contenteditable="true"], [role="slider"]',
+        )
       ) {
         return;
       }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/components/VideoPlayer/NetflixStylePlayer.tsx` around lines 66 -
104, Update the handleKeyDown document listener in NetflixStylePlayer so it
ignores shortcuts whenever the focused element is any interactive control,
including BUTTON, A, SELECT, and other elements with interactive roles or
tabIndex, in addition to INPUT, TEXTAREA, and contenteditable elements. Return
before the switch to prevent native control activation from also triggering
togglePlay, toggleMute, or other global shortcuts.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@frontend/src/components/VideoPlayer/__tests__/NetflixStylePlayer.test.tsx`:
- Around line 367-388: Extend the volume accessibility test to cover the slider:
update the Slider mock used by NetflixStylePlayer tests to forward its
aria-label prop, then assert that getByRole('slider', { name: 'Volume' }) is
present in the control-label test alongside the button assertions.

In `@frontend/src/components/VideoPlayer/NetflixStylePlayer.tsx`:
- Around line 39-55: Controls currently hide after the temporary reveal timeout
even when keyboard focus remains inside the player. Add separate focus-within
state, set it on the player’s focus handler and clear it only on blur when focus
moves outside the player; include this state in controlsVisible and update the
relevant focus/blur handlers and control visibility logic so focused controls
remain visible.

---

Outside diff comments:
In `@frontend/src/components/VideoPlayer/NetflixStylePlayer.tsx`:
- Around line 66-104: Update the handleKeyDown document listener in
NetflixStylePlayer so it ignores shortcuts whenever the focused element is any
interactive control, including BUTTON, A, SELECT, and other elements with
interactive roles or tabIndex, in addition to INPUT, TEXTAREA, and
contenteditable elements. Return before the switch to prevent native control
activation from also triggering togglePlay, toggleMute, or other global
shortcuts.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 8e9a59a5-ee8e-4c38-a6d7-33d61b972a44

📥 Commits

Reviewing files that changed from the base of the PR and between ffc0d48 and ac752e9.

📒 Files selected for processing (3)
  • frontend/src/components/VideoPlayer/NetflixStylePlayer.tsx
  • frontend/src/components/VideoPlayer/__tests__/NetflixStylePlayer.test.tsx
  • frontend/src/components/ui/Slider.tsx

Comment thread frontend/src/components/VideoPlayer/NetflixStylePlayer.tsx
… guard, slider label test

- Keep controls visible while keyboard focus remains inside the player:
  track focus-within state on the container (cleared only when focus
  leaves the player) and include it in controlsVisible, so a focused
  control can no longer go invisible mid-interaction.
- Ignore global keyboard shortcuts while any interactive control is
  focused (button, select, link, slider, etc.), preventing Space on a
  focused button from both activating it natively and firing the
  shortcut (e.g. double play-toggle).
- Forward aria-label through the test Slider mock and assert the volume
  slider's accessible name; add a regression test for the focus-within
  visibility behaviour.

@rohan-pandeyy rohan-pandeyy left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please review and compress all those comments which are going too long.

Comment thread frontend/src/components/VideoPlayer/NetflixStylePlayer.tsx Outdated
Maintainer asked to keep comments to 1-2 lines max; trimmed the four
that ran 2-4 lines down to single lines without losing the intent.
@VanshajPoonia

VanshajPoonia commented Jul 11, 2026

Copy link
Copy Markdown
Contributor Author

Heads up on the failing Linting check, it's not related to this PR's changes.

The check fails on format:check flagging src/components/Media/ZoomableImage.tsx, a file this PR never touches (diff is scoped to NetflixStylePlayer.tsx, NetflixStylePlayer.test.tsx, and ui/Slider.tsx). A few things I checked:

  • eslint:check passes clean, the failure is purely in prettier --check.
  • Running prettier --write on ZoomableImage.tsx locally produces zero changes (confirmed with the exact dependency versions from package-lock.json, on both Node 18 and Node 24).
  • The lockfile pins the exact same Tailwind version (4.1.16, including the Linux-specific @tailwindcss/oxide binary) across all platforms, so it's not a dependency-version drift.
  • Timing is the interesting part: the same commit's Linting check passed 3 times (~06:50-07:00 UTC) and has failed 3 times in a row since ~16:42 UTC, with zero code changes to the flagged file in between. That points to something changing in the CI environment itself (possibly the Tailwind v4 oxide native engine producing non-deterministic class ordering on the Linux runner) rather than anything in this diff.

Since the workflow uses npm install rather than npm ci, it might be worth locking that down, but even the exact-pinned oxide binary seems to be the likely culprit here.

Given this looks environment-side, could you take a look or re-run the check when you get a chance? Happy to dig further if useful, flagging in case it's also blocking other open PRs.

@rohan-pandeyy
rohan-pandeyy merged commit cbf6eeb into AOSSIE-Org:main Jul 19, 2026
10 of 11 checks passed
@rohan-pandeyy

Copy link
Copy Markdown
Member

Thanks for your contribution @VanshajPoonia

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working frontend

Projects

None yet

Development

Successfully merging this pull request may close these issues.

BUG: NetflixStylePlayer - render title/description, accessible seek bar, and controls-visibility UX (follow-up to #1329)

2 participants