Theme studio

Design a theme, preview it live, then export it. Saved in this browser.

Quick picks #10b981
Generated scale
50100200300400500600700800900
Some text is below AA

VideoPlayer

  • Stable
  • WCAG 2.2 evidence
  • RTL

A video with a poster, Nexera controls and captions. A shell around the native <video>: it calls play(), pause(), currentTime, volume, muted, requestFullscreen() and requestPictureInPicture() and mirrors the element's events in its state. The library never hosts or fetches media. Accessibility: a named region. Every control is a button or slider reachable by Tab (WCAG 2.1.1), with the shortcuts K / Space, M, C, F and arrows while focus is inside the player only (2.1.4, never global). Captions come from tracks (WebVTT), are toggled with C or the captions button and drawn in the Figma box (1.2.2). No autoplay with sound (1.4.2); autoplay is muted and skipped with reduced motion, and pause is always one key away (2.2.2). Loading is announced by the spinner (4.1.3) and errors as an alert. When the control that had focus disappears (the poster play button once playback starts, the controls at the end), focus moves to the new primary action instead of being lost (2.4.3). The spinner animates only when motion is allowed (2.3.3). Media colours are the same in Light and Dark; the controls keep 3:1 over any frame (1.4.11). Consumer duties: captions and a transcript (1.2.1 to 1.2.5: audio description where the picture carries information), the poster's text alternative through title / description, letting people stop an "Up next" timer, and translated labels.

import { VideoPlayer } from "@nexera-ui/react";
Loading example…
6
examples
28
props
10
live controls
1
platform
11
WCAG criteria
1
block uses it

Try every prop. Copy the code.

Change the props and the code updates. Check light and dark, LTR and RTL, and phone width.

Loading…
description
isLoading
isInvalid
autoPlay
loop
preload
crossOrigin
controlsLayout
keyboardShortcuts
title
Generated code
import { VideoPlayer } from "@nexera-ui/react";

<VideoPlayer />

Examples 5

The same examples as Storybook, rendered live. Open Code to copy one.

With up next

At the end: Replay and an "Up next" card. Let the 8-second sample play to the end.

Loading example…

Compact controls

controlsLayout="compact" for narrow players.

Loading example…

Loading

isLoading: a spinner announced as "Loading video" over a 60 % scrim.

Loading example…

Error

isInvalid: announced as an alert, with Retry. The player also shows it when the media fails.

Loading example…

Fallback slot

Without a poster image the fallback slot shows on the poster.

Loading example…

Props 28

Press "Try it" on a card to load that prop into the playground.

28 props shown

srcNexera
string

Video URL. The library never hosts or fetches media itself: pass a URL your app serves.

Default –
sourcesNexera
readonly VideoPlayerSource[]

Several formats of the same video (<source> elements), tried in order.

Default –
posterNexera
string

Poster image URL shown before playback.

Default –
fallbackNexera
ReactNode

The Figma Photo placeholder slot: shown in the poster state when there is no poster image. Decorative.

Default –
descriptionNexera
ReactNode

Second line under the title on the poster.

Default –
captionNexera
ReactNode

Caption text to show above the controls, when you render captions yourself. Without it, the active cue of the captions track is shown while captions are on.

Default –
tracksNexera
readonly VideoPlayerTrack[]

Captions and subtitles (<track> elements). With at least one, the captions toggle appears (C toggles it) and the cues are drawn in the Figma Captions box. Required for prerecorded speech (WCAG 1.2.2).

Default –
upNextNexera
VideoPlayerUpNext

The "Up next" card of the ended state.

Default –
isLoadingNexera
boolean

Shows the loading state whatever the media does, for example while you fetch a signed URL. The player also shows it on its own while the media waits for data.

Default false
isInvalidNexera
boolean

Shows the error state whatever the media does, for example when your API refuses the video. The player also shows it on its own when the media fails to load.

Default false
autoPlayNexera
boolean

Starts playback on load, always muted (no autoplay with sound, WCAG 1.4.2) and never when the user prefers reduced motion (2.2.2, 2.3.3). The controls let people pause and unmute.

Default false
loopNexera
boolean

Plays again from the start at the end.

Default false
preloadNexera
"none" | "metadata" | "auto"

How much to load before playback (native preload).

Default metadata
crossOriginNexera
"anonymous" | "use-credentials"

CORS mode of the video and track requests (native crossOrigin); captions from another origin need it.

Default –
controlsLayoutNexera
"full" | "compact"

Controls layout: full, or compact for narrow players.

Default full
seekStepNexera
number

Seconds moved by the arrow keys and the back button.

Default 5
keyboardShortcutsNexera
boolean

Keyboard shortcuts while focus is in the player (K / Space, M, C, F, arrows); never global. false turns them off (WCAG 2.1.4).

Default true
onPlayingChangeNexera
(isPlaying: boolean) => void

Called when playback starts (true) or stops (false).

Default –
onEndedNexera
() => void

Called when the video reaches its end.

Default –
onRetryNexera
() => void

Called when Retry is pressed. Without it, the player reloads the video and plays.

Default –
onSettingsPressNexera
() => void

Called when Settings is pressed (full controls): open your quality / speed menu. The button shows when set.

Default –
videoRefNexera
Ref<HTMLVideoElement>

Ref to the native <video>, for anything the player does not cover (playbackRate, textTracks, events).

Default –
labelsNexera
Partial<VideoPlayerLabels>

Texts; English defaults. Translate them.

Default –
classNameNexera
string

Extra classes for the root, merged last so they win over the defaults.

Default –
styleNexera
CSSProperties

Inline style for the root.

Default –
titleNexera
ReactNode

Title of the video, shown on the poster; it names the player. Title of the video, shown on the poster.

Default –
aria-labelNexera
string

Accessible name; replaces the title as the player's name. Accessible name of the player when there is no title. Translate it. Accessible name; aria-labelledby wins.

Default –
aria-labelledbyNexera
string

Id(s) of element(s) that name the player; wins over title and aria-label. Id(s) of element(s) that name the player; wins over aria-label. Id(s) of visible element(s) that name the player.

Default –

* Required. React Aria props shown are the ones most apps use; the component accepts the rest of its React Aria props too.

Accessible by default.

Built on React Aria, and covered by the WCAG 2.2 evidence generated on every build.

WCAG 2.2 evidence

11 direct · 0 supporting
  • 1.1.1Non-text ContentLevel A · tested directly
  • 1.2.2Captions (Prerecorded)Level A · tested directly
  • 1.3.1Info and RelationshipsLevel A · tested directly
  • 1.4.2Audio ControlLevel A · tested directly
  • 2.1.1KeyboardLevel A · tested directly
  • 2.1.4Character Key ShortcutsLevel A · tested directly
  • 2.2.2Pause, Stop, HideLevel A · tested directly
  • 2.3.3Animation from InteractionsLevel AAA · tested directly
  • 2.4.3Focus OrderLevel A · tested directly
  • 4.1.2Name, Role, ValueLevel A · tested directly
  • 4.1.3Status MessagesLevel AA · tested directly

Fits any width.

Nexera components respond to the space they are given. Drag the corner of the frame, or pick a width.

0 px · drag the corner

Styling hooks

Pass className to add Tailwind classes (merged last). State is exposed as data attributes, so you can style it with variants like data-pressed:.

  • data-fullscreen
  • data-hovered
  • data-pressed
Usage
<VideoPlayer className="data-fullscreen:opacity-90 shadow-sm" />

Used in blocks

Related components