npm
v1.6.0Captions now clear the controls

Every video source, one React component

Local files, HLS, YouTube, Vimeo and Bilibili behind a single API — with captions, chapters, playlists and analytics callbacks already in the box. 14.0 kB gzipped, and nothing else in your lockfile.

npm i vplayer-react

controlsVariant="minimal" — One row, scrubber between elapsed and remaining time

No More Barrier to Cross

Local MP4 playlist with chapters, captions, ref API, and all callbacks

Ref API Controls

Feature Toggles

initialTime

Track

1 / 2

Chapter

—

Volume

100%

Buffered

0%

Milestones

25%50%75%100%

Callback Log

Interact with the player to see callback events here

Brand Accent Color

14.0kB

minified + gzipped

0

runtime dependencies

5

source types, one component

18+

React, as a peer dependency

Everything a real player needs

Not a <video> tag with a skin on it — the parts you would otherwise build yourself, in the same component.

Sources

One API, five source types
Local and remote media files, HLS manifests, YouTube, Vimeo and Bilibili — the component works out which it is and renders the right thing.
Lazy embeds
Platform iframes stay unmounted behind the poster until someone actually presses play, so a page full of players costs one image each.
Playlists
Pass an array for prev/next and auto-advance, or drive the index yourself with activeIndex and onIndexChange.
Native HLS
Plays where the browser supports it, and surfaces a clear error overlay where it doesn’t — instead of failing silently.

The viewing experience

Three control skins
Classic, minimal and floating carry identical controls — the difference is layout and surface. Each adapts down to a 300px player without a control ever losing its hit area.
Captions that clear the controls
Cues are drawn inside the picture and lift above the bar while it’s on screen, so they stay readable — even for a wide clip fullscreened on a portrait phone.
Chapters and scrub previews
Tick marks with hover labels, Shift+Arrow chapter jumps, and sprite-sheet frame previews while scrubbing.
Keyboard and touch, properly
Scoped shortcuts that never hijack the page, 44px hit areas, touch scrubbing, PiP, and a reduced-motion path for every transition.
Errors that recover
A failed load names what the viewer can check — missing file, blocked by the server, unplayable codec — and offers a retry instead of a dead end.

The developer experience

Zero runtime dependencies
Pure React and inline styles. No CSS file to import, nothing to configure, nothing else pulled into your lockfile.
Analytics callbacks
onPlay, onSeek, onBuffer, onMilestone, onChapterChange, onVolumeChange, onError and a dozen more — enough to instrument playback without a wrapper.
Ref API
play, pause, seek, setVolume, toggleMute, toggleFullscreen, and an escape hatch to the underlying media element.
Controlled or uncontrolled
playing, volume, muted, playbackRate and the playlist index all accept controlled props — or leave them off and the player keeps its own state.
Clip mode and resume
initialTime resumes where a viewer left off, endTime plays an excerpt out of a longer file, and persistVolume remembers the level across reloads.
Typed and server-safe
Full TypeScript types, matching ESM and CJS declarations, and a “use client” directive so importing from a Server Component just works.

Working in a minute

Install, import, pass a URL. Everything below that is optional.

Install
npm i vplayer-react
  • React 18 or newer, as a peer dependency
  • No stylesheet to import and nothing to configure
  • Ships ESM and CJS with matching type declarations
  • Carries “use client”, so a Server Component can import it
Quick start
import { VPlayer } from 'vplayer-react';

export default function Page() {
  return (
    <VPlayer
      src="https://example.com/video.mp4"
      poster="/poster.jpg"
      title="My Video"
      accentColor="#ff5705"
      controlsVariant="minimal"
    />
  );
}

One component, five kinds of URL. Platform links become lazy embeds behind a poster; media files and HLS manifests get the full custom control bar.

Any source
// Local or remote media file
<VPlayer src="/clip.mp4" />

// HLS — plays natively where the browser supports it,
// with a clear error overlay where it doesn’t
<VPlayer src="https://cdn.example.com/master.m3u8" />

// Platform links — lazy-loaded iframes behind the poster
<VPlayer src="https://youtu.be/OZjOHE_Y8vY" />
<VPlayer src="https://vimeo.com/347119375" />
<VPlayer src="https://www.bilibili.com/video/BV1Tm421n7WT/" />

// Check before you render
VPlayer.canPlay("https://youtu.be/OZjOHE_Y8vY"); // true

The full prop reference — every callback, every type — lives in the README.

Keyboard, scoped

Shortcuts fire only while the player has focus, so a page with three players — or a search box — never loses a keystroke to the video. Every binding is remappable through the keymap prop, and any of them can be switched off.

Space / K
Play or pause
F
Toggle fullscreen
M
Toggle mute
← / →
Rewind or forward 5s
Shift + ← / →
Previous or next chapter
↑ / ↓
Volume up or down
0–9
Seek to 0%–90%
< / >
Decrease or increase speed
?
Toggle the shortcuts overlay
Esc
Close menus and overlays

Questions

The ones worth answering before you install anything.

Reading this with an agent? There is a markdown mirror of the whole page at /llms-full.txt, and a short index at /llms.txt.

Which React video player handles MP4 and YouTube in the same component?

vplayer-react does. Pass any URL to src and the component works out what it is: media files and HLS manifests render with the full custom control bar, while YouTube, Vimeo and Bilibili links become lazy-loaded embeds behind the poster. VPlayer.canPlay(url) tells you in advance whether a URL is recognised.

How large is vplayer-react?

14.0 kB minified and gzipped, with zero runtime dependencies — nothing but React itself enters your lockfile, and there is no stylesheet to import. The component is styled with inline styles plus one small injected stylesheet for hover, focus and reduced-motion rules.

Does it work with Next.js and React Server Components?

Yes. The published bundles carry the "use client" directive, so importing vplayer-react directly inside a Server Component works without a wrapper. It ships both ESM and CommonJS builds with matching TypeScript declarations, and requires React 18 or newer as a peer dependency.

Does it support HLS streams?

Yes, where the browser plays HLS natively — Safari, iOS and some Chromium builds. Pass an .m3u8 URL like any other source. In browsers without native support the player surfaces a clear error overlay rather than failing silently, so you can decide whether to ship an HLS polyfill alongside it.

How do I add subtitles or closed captions?

Pass a tracks array of WebVTT files and a CC picker appears in the control bar. The player renders the cues itself rather than leaving them to the browser, so they sit inside the picture, rise to clear the control bar while it is on screen, and stay put when a widescreen clip is fullscreened on a portrait phone. captionStyle restyles them without any CSS file.

Is it accessible?

Keyboard shortcuts are scoped to the player, so a page with three players — or a search box — never loses a keystroke to the video. Every control is a real button with an accessible name and a 40×44px hit area, the seek and volume sliders implement the ARIA slider pattern, hidden controls leave the tab order, and every transition has a prefers-reduced-motion path.

Can I drive playback from my own state?

Yes. playing, volume, muted, playbackRate and the playlist index all accept controlled props, and there is an imperative handle with play(), pause(), seek(), setVolume(), toggleMute(), toggleFullscreen() and an escape hatch to the underlying media element. Leave the props off and the player keeps its own state.

Can I change how the controls look?

controlsVariant picks between three skins carrying identical controls: classic (full-width scrim with the scrubber on its own row), minimal (one row with the scrubber inline between elapsed and remaining time) and floating (that row inside a detached, blurred pill). accentColor and iconColor handle brand colour, and each skin adapts down to a 300px-wide player.