Installation
Install the package via npm or yarn:
npm install @frameset/plex-playeror with yarn:
yarn add @frameset/plex-playerQuick Start
Import the component and styles, then use it in your React application:
import { PlexVideoPlayer } from '@frameset/plex-player';
import '@frameset/plex-player/styles.css';
function App() {
return (
<PlexVideoPlayer
src="https://example.com/video.mp4"
poster="https://example.com/poster.jpg"
autoPlay={false}
accentColor="#e5a00d"
theme="dark"
/>
);
}Basic Usage
Here's a live example of the player with common props:
<PlexVideoPlayer
src="https://example.com/video.mp4"
poster="https://example.com/poster.jpg"
autoPlay={false}
muted={false}
pip={true}
fullscreen={true}
playbackSpeed={true}
accentColor="#e5a00d"
theme="dark"
onPlay={() => console.log('Video started')}
onEnded={() => console.log('Video ended')}
/>Video Props
Core props for video source and behavior:
| Prop | Type | Description |
|---|---|---|
| src | string | VideoSource[] | Video source URL or array of sources with quality options |
| poster | string | Poster image URL shown before playback |
| autoPlay | boolean | Auto-start playback when ready |
| muted | boolean | Start with muted audio |
| loop | boolean | Loop video playback |
| preload | 'none' | 'metadata' | 'auto' | Video preload behavior |
| width | number | string | Player width |
| height | number | string | Player height |
Control Props
Props for enabling/disabling player controls:
| Prop | Type | Description |
|---|---|---|
| controls | boolean | Show player controls |
| pip | boolean | Enable Picture-in-Picture button |
| fullscreen | boolean | Enable fullscreen button |
| playbackSpeed | boolean | Enable playback speed control |
| playbackSpeeds | number[] | Available playback speeds |
| volume | boolean | Enable volume control |
| initialVolume | number | Initial volume (0-1) |
| qualitySelector | boolean | Enable quality selector (requires multiple sources) |
| keyboard | boolean | Enable keyboard shortcuts |
| clickToPlay | boolean | Click on video to play/pause |
| doubleClickFullscreen | boolean | Double-click to toggle fullscreen |
Style Props
Props for customizing the player appearance:
| Prop | Type | Description |
|---|---|---|
| accentColor | string | Accent color for progress bar and buttons |
| theme | 'dark' | 'light' | 'auto' | Control bar color theme |
| className | string | Custom CSS class for the container |
| style | React.CSSProperties | Inline styles for the container |
| controlsTimeout | number | Timeout before hiding controls (ms) |
💡 Tip: Custom Accent Colors
The accentColor prop accepts any valid CSS color value. Use your brand color to match the player with your site design.
Event Callbacks
Callbacks for handling player events:
| Prop | Type | Description |
|---|---|---|
| onPlay | () => void | Called when playback starts |
| onPause | () => void | Called when playback pauses |
| onEnded | () => void | Called when video ends |
| onTimeUpdate | (time: number) => void | Called on time update with current time |
| onProgress | (buffered: number) => void | Called on buffer progress |
| onVolumeChange | (volume: number, muted: boolean) => void | Called when volume changes |
| onFullscreenChange | (isFullscreen: boolean) => void | Called on fullscreen toggle |
| onPipChange | (isPip: boolean) => void | Called on PiP toggle |
| onQualityChange | (quality: string) => void | Called when quality changes |
| onError | (error: MediaError | null) => void | Called on playback error |
| onReady | () => void | Called when player is ready |
<PlexVideoPlayer
src="https://example.com/video.mp4"
onPlay={() => analytics.track('video_play')}
onPause={() => analytics.track('video_pause')}
onEnded={() => showNextVideo()}
onTimeUpdate={(time) => saveProgress(time)}
onError={(error) => console.error('Video error:', error)}
/>Playlist
Create a playlist with multiple videos. The player will automatically play the next video when the current one ends.
import { PlexVideoPlayer } from '@frameset/plex-player';
import '@frameset/plex-player/styles.css';
const playlist = [
{
id: '1',
src: 'https://example.com/video1.mp4',
title: 'Episode 1',
poster: 'https://example.com/poster1.jpg',
},
{
id: '2',
src: 'https://example.com/video2.mp4',
title: 'Episode 2',
poster: 'https://example.com/poster2.jpg',
},
{
id: '3',
src: 'https://example.com/video3.mp4',
title: 'Episode 3',
poster: 'https://example.com/poster3.jpg',
},
];
function App() {
return (
<PlexVideoPlayer
src=""
playlist={playlist}
onPlaylistItemChange={(index, item) => {
console.log(`Now playing: ${item.title}`);
}}
/>
);
}PlaylistItem Type
interface PlaylistItem {
id: string; // Unique identifier
src: string; // Video source URL
title: string; // Video title
poster?: string; // Poster image URL (optional)
duration?: number; // Duration in seconds (optional)
}Quality Selector
Provide multiple video sources with different quality options:
<PlexVideoPlayer
src={[
{ src: 'video-1080p.mp4', quality: '1080p', label: 'Full HD' },
{ src: 'video-720p.mp4', quality: '720p', label: 'HD' },
{ src: 'video-480p.mp4', quality: '480p', label: 'SD' },
{ src: 'video-360p.mp4', quality: '360p', label: 'Low' },
]}
qualitySelector={true}
onQualityChange={(quality) => console.log(`Quality: ${quality}`)}
/>Subtitles
Add subtitle tracks using the textTracks prop:
<PlexVideoPlayer
src="https://example.com/video.mp4"
textTracks={[
{
src: '/subtitles/en.vtt',
kind: 'subtitles',
srclang: 'en',
label: 'English',
default: true,
},
{
src: '/subtitles/es.vtt',
kind: 'subtitles',
srclang: 'es',
label: 'Español',
},
{
src: '/subtitles/uk.vtt',
kind: 'subtitles',
srclang: 'uk',
label: 'Українська',
},
]}
/>VAST Ads
Integrate video ads using VAST 2.0/3.0/4.0:
<PlexVideoPlayer
src="https://example.com/video.mp4"
vast={{
url: 'https://example.com/vast.xml',
position: 'preroll',
skipDelay: 5, // Skip button after 5 seconds
}}
onAdStart={(ad) => console.log('Ad started:', ad.title)}
onAdEnd={() => console.log('Ad ended')}
onAdSkip={() => console.log('Ad skipped')}
/>
// Multiple ads
<PlexVideoPlayer
src="https://example.com/video.mp4"
vast={[
{ url: 'preroll.xml', position: 'preroll' },
{ url: 'midroll.xml', position: 'midroll', midrollTime: 60 },
{ url: 'postroll.xml', position: 'postroll' },
]}
/>Keyboard Shortcuts
Built-in keyboard shortcuts for better accessibility:
| Key | Action |
|---|---|
| Space / K | Toggle play/pause |
| ← | Rewind 10 seconds |
| → | Forward 10 seconds |
| Shift + ← | Rewind 30 seconds |
| Shift + → | Forward 30 seconds |
| ↑ | Volume up |
| ↓ | Volume down |
| M | Toggle mute |
| F | Toggle fullscreen |
| P | Toggle Picture-in-Picture |
| 0-9 | Seek to 0%-90% of video |
Custom Hotkeys
<PlexVideoPlayer
src="https://example.com/video.mp4"
keyboard={true}
hotkeys={{
play: 'Space',
mute: 'm',
fullscreen: 'f',
pip: 'p',
seekForward: 'ArrowRight',
seekBackward: 'ArrowLeft',
volumeUp: 'ArrowUp',
volumeDown: 'ArrowDown',
}}
/>Ref Methods
Access player methods via ref for programmatic control:
import { useRef } from 'react';
import { PlexVideoPlayer, PlexVideoPlayerRef } from '@frameset/plex-player';
function App() {
const playerRef = useRef<PlexVideoPlayerRef>(null);
const handleCustomPlay = () => {
playerRef.current?.play();
};
const handleSeekTo = (time: number) => {
playerRef.current?.seek(time);
};
const handleSkipIntro = () => {
playerRef.current?.seek(30); // Skip to 30 seconds
};
return (
<>
<PlexVideoPlayer
ref={playerRef}
src="https://example.com/video.mp4"
/>
<button onClick={handleCustomPlay}>Play</button>
<button onClick={handleSkipIntro}>Skip Intro</button>
</>
);
}Available Methods
| Prop | Type | Description |
|---|---|---|
| play() | Promise<void> | Start playback |
| pause() | void | Pause playback |
| stop() | void | Stop and reset playback |
| seek(time) | void | Seek to specific time (seconds) |
| setVolume(volume) | void | Set volume (0-1) |
| mute() / unmute() | void | Mute/unmute audio |
| toggleMute() | void | Toggle mute state |
| enterFullscreen() | Promise<void> | Enter fullscreen mode |
| exitFullscreen() | Promise<void> | Exit fullscreen mode |
| toggleFullscreen() | Promise<void> | Toggle fullscreen |
| enterPip() / exitPip() | Promise<void> | Enter/exit PiP mode |
| setPlaybackRate(rate) | void | Set playback speed |
| getCurrentTime() | number | Get current time |
| getDuration() | number | Get video duration |
| getVideoElement() | HTMLVideoElement | null | Get underlying video element |
Hooks
Custom hooks for building your own player UI:
usePlayer
Hook for managing video player state:
import { usePlayer } from '@frameset/plex-player';
function CustomPlayer() {
const {
state,
videoRef,
containerRef,
play,
pause,
togglePlay,
seek,
setVolume,
toggleMute,
toggleFullscreen,
togglePip,
} = usePlayer({
autoPlay: false,
muted: false,
volume: 1,
});
return (
<div ref={containerRef}>
<video ref={videoRef} src="video.mp4" />
<button onClick={togglePlay}>
{state.isPlaying ? 'Pause' : 'Play'}
</button>
<span>{state.currentTime} / {state.duration}</span>
</div>
);
}useKeyboard
Hook for keyboard shortcuts:
import { useKeyboard } from '@frameset/plex-player';
useKeyboard({
enabled: true,
containerRef: containerRef,
onPlay: togglePlay,
onMute: toggleMute,
onFullscreen: toggleFullscreen,
onPip: togglePip,
onSeek: (delta) => seek(currentTime + delta),
onVolume: (delta) => setVolume(volume + delta),
});Utilities
Helper functions exported from the package:
import {
formatTime, // (seconds) => "1:23:45"
parseTime, // ("1:23:45") => seconds
percentage, // (value, total) => percentage
clamp, // (value, min, max) => clamped value
throttle, // Throttle function execution
debounce, // Debounce function execution
isFullscreenSupported,
isPipSupported,
isMobile,
isTouchDevice,
detectVideoType, // Detect MIME type from URL
canPlayType, // Check browser support for format
} from '@frameset/plex-player';
// Example
const time = formatTime(3723); // "1:02:03"
const seconds = parseTime("1:02:03"); // 3723TypeScript Types
All types are exported for TypeScript users:
import type {
PlexVideoPlayerProps,
PlexVideoPlayerRef,
PlayerState,
VideoSource,
TextTrack,
VastConfig,
VastAdInfo,
PlaylistItem,
HotkeyConfig,
UsePlayerOptions,
UsePlayerReturn,
} from '@frameset/plex-player';