Passer au contenu principal

VideoPlayer

Implemented

Video playback frame wrapping native <video controls> with aspect-ratio enforcement (16:9, 4:3, 1:1), poster, loading skeleton, and error fallback. Keyboard: Space (play/pause), ←/→ (seek ±5s), ↑/↓ (volume ±0.1), f (fullscreen), c (captions toggle — case-insensitive). prefers-reduced-motion guard blocks autoplay. Error state (role=alert) on playback failure.

Categorymolecules
Sourcepatterns/molecules/videoplayer.html
AI HintUse for video playback with aspect-ratio enforcement and keyboard controls. Wraps native <video controls> — no custom scrub bar or progress UI. For audio-only, use AudioPlayer. Autoplay degrades to paused when policy-blocked; pair with muted=true.

Native-controls video player with keyboard map and error fallback.

VideoPlayer

Media & playback — molecule

Native-controls video player with keyboard map and error fallback.

Usage

VideoPlayer is self-managing: give it a real src and an accessible label, and it handles the loading skeleton, the keyboard map and the error fallback itself. The native control bar (on by default) handles play, seek, volume and fullscreen;aspectRatio fixes the box shape and poster shows a frame before first load.

import { VideoPlayer } from '@epasslive/design-system'

// Default 16:9 with poster
<VideoPlayer
  src="/media/trailer.mp4"
  label="Event trailer"
  poster="/media/trailer.jpg"
/>

// Square social embed (1:1), muted loop
<VideoPlayer
  src={clip.url}
  label={clip.title}
  aspectRatio="1:1"
  muted
  loop
/>

Keyboard

KeyAction
SpaceToggle play / pause (region focused)
←Seek back 5 seconds
→Seek forward 5 seconds
↑Volume up (+0.1)
↓Volume down (−0.1)
fToggle fullscreen (case-insensitive)
cToggle first declared text track, if any (case-insensitive)

Honest notes (current limitations)

  • Autoplay policy rejection degrades to paused, not error. A NotAllowedError from play() (browser blocking ungestured playback) leaves a healthy video paused on its poster — the error state is reserved for genuine media failures. Autoplay with muted is safe to attempt; unmuted autoplay will typically just stay paused. No demo or story here uses autoplay.
  • c captions toggle is near-inert. The key toggles textTracks[0], but only affects tracks embedded in the source file. The component renders no <track> element and offers no tracks prop — for ordinary sources, c is a no-op. WCAG 1.2.2 remains the consumer's responsibility.
  • controls={false} leaves keyboard-only control with no visible play CTA. The molecule renders no play button. Keep controls on unless you provide your own chrome.
  • No custom scrub bar exists. Seeking is the native control bar or ← / → keys only. The molecule has no progress API and no timecode — live time and seeking are the browser's.
  • Hardcoded playsInline + preload="metadata". Both are fixed behavior consumers cannot change via props.
  • The error fallback reflects genuine media failures. The third preview above uses a 404 source on purpose so the inline role="alert" fallback renders for the right reason — never by autoplay (a policy-blocked autoplay now stays paused instead).

Props

Prop
Type
Default
Description
src*
string
—

Video source URL passed to the native <video> element (HTTPS or same-app path).

label*
string
—

Accessible name for the player region; also prefixes the error fallback text.

poster
string
—

Poster frame URL shown before first load/play.

autoplay
boolean
—

Attempt playback on mount. Suppressed when the user prefers reduced motion. Policy-blocked autoplay degrades to paused, not the error state — pair with muted for reliable ungestured autoplay. Default false.

muted
boolean
—

Start muted. Also the only autoplay mode browsers reliably allow ungestured. Default false.

controls
boolean
—

Show the native control bar. false leaves keyboard-only operation — the molecule renders no custom play UI. Default true.

loop
boolean
—

Replay from the start when the video ends. Default false.

aspectRatio
"16:9" | "4:3" | "1:1"
—

Fixed box ratio (aspect-video / aspect-[4/3] / aspect-square), applied to both the frame and the error fallback. Default "16:9".

className
string
—

Additional classes on the root element.

id
string
—

Stable root id; falls back to an SSR-safe useId() value.

Props

Preview

VideoPlayer

Prop
Type
Required
Default
Description
src
string
Required
—

Video source URL (MP4, WebM, or HLS manifest). Required.

poster
string
Optional
—

Poster image URL shown before playback starts or while loading.

autoplay
boolean
Optional
false

Attempt autoplay on mount. Blocked by prefers-reduced-motion. Policy-blocked autoplay (NotAllowedError) degrades gracefully to paused — error state reserved for genuine media failures. Pair with muted=true for reliable autoplay.

muted
boolean
Optional
false

Start muted. Required for autoplay to succeed under most browser policies.

controls
boolean
Optional
true

Show native video controls. When false, keyboard-only control (Space/arrows/f/c) with no visible play CTA.

loop
boolean
Optional
false

Loop playback continuously.

aspectRatio
VideoAspectRatio
Optional
"16:9"

Aspect ratio: '16:9' (default), '4:3', or '1:1'. Enforced via CSS aspect-ratio.

label
string
Required
—

Accessible label for the video container (aria-label). Required for a11y.

className
string
Optional
—

Additional CSS classes appended to the wrapper.

id
string
Optional
—

Custom id; auto-generated via React.useId() if omitted.

Quick use:<VideoPlayer />

Accessibility

ARIA roleapplication

a11y

3 rules

WCAG 2.1.1

Keyboard: Space (play/pause), ←/→ (seek ±5s), ↑/↓ (volume ±0.1), f (fullscreen), c (captions toggle — case-insensitive)

WCAG 2.3.3

prefers-reduced-motion: autoplay blocked when user opts out of motion

WCAG 4.1.3

Error fallback: role=alert with AlertIcon on playback failure

layout

1 rule

Design system

Aspect ratios: 16:9 (default), 4:3, 1:1 enforced via CSS aspect-ratio

Usage

Import

tsxSnippet
import { VideoPlayer } from "@epasslive/design-system"

Example 1

tsxSnippet
<VideoPlayer src="https://example.com/video.mp4" label="Product demo" />

Example 2

tsxSnippet
<VideoPlayer src="https://example.com/video.mp4" poster="/poster.jpg" aspectRatio="1:1" label="Square preview" />

Anti-patterns

— Do not use for audio-only content (use AudioPlayer)

— Do not set autoplay without muted — browsers block unmuted autoplay

— Do not expect custom scrub bar — seeking is native controls or arrow keys only

Design System v4.1.0 | ePassLive