VideoPlayer
The main video player component, wrapping Shaka Player for streaming and MP4 playback.
Basic Usage
import { VideoPlayer } from "@elcto/player";
<VideoPlayer
src="https://storage.example.com/videos/demo.mp4"
poster="https://storage.example.com/images/poster.jpg"
controls
autoPlay={false}
/>
With Resume Playback
Resume playback stores the video position in localStorage. Requires user consent to functional cookies via @elcto/cookies-consent.
import { VideoPlayer } from "@elcto/player";
<VideoPlayer
src={videoUrl}
videoId="unique-video-123"
rememberPosition
saveInterval={5000} // Save every 5 seconds
resumeThreshold={30} // Clear position if <30s from end
/>
Custom Theme
Use design tokens or custom values:
<VideoPlayer
src={videoUrl}
theme={{
primaryColor: "var(--brand)",
backgroundColor: "rgba(0, 0, 0, 0.85)",
seekBarHeight: 4,
seekBarHoverHeight: 8,
controlBarHeight: 48,
}}
controls={["play_pause", "volume", "seek_bar", "current_time", "spacer", "quality", "fullscreen"]}
/>
Custom Controls
Specify which controls to show:
<VideoPlayer
src={videoUrl}
controls={[
"play_pause",
"mute",
"volume",
"current_time",
"seek_bar",
"duration",
"spacer",
"playback_rate",
"quality",
"picture_in_picture",
"fullscreen"
]}
/>
Event Handling
<VideoPlayer
src={videoUrl}
onReady={(player) => console.log("Player ready", player)}
onPlay={() => console.log("Started playing")}
onPause={() => console.log("Paused")}
onEnded={() => console.log("Playback ended")}
onError={(error) => console.error("Error:", error)}
onTimeUpdate={(time) => console.log("Current time:", time)}
onProgress={(buffered) => console.log("Buffered:", buffered)}
/>
Props
Core Props
| Prop | Type | Default | Description |
|---|---|---|---|
src | string | required | Video source URL (MP4, HLS, DASH) |
poster | string | - | Poster image URL |
videoId | string | - | Unique ID for resume playback (defaults to src hash) |
Playback Props
| Prop | Type | Default | Description |
|---|---|---|---|
autoPlay | boolean | false | Auto-start playback |
muted | boolean | false | Start muted |
loop | boolean | false | Loop playback |
playbackRate | number | 1 | Playback speed |
volume | number | 1 | Volume (0-1) |
startTime | number | - | Start position in seconds |
Resume Playback Props
| Prop | Type | Default | Description |
|---|---|---|---|
rememberPosition | boolean | false | Enable resume from last position |
saveInterval | number | 5000 | Position save interval (ms) |
resumeThreshold | number | 30 | Seconds from end to clear saved position |
Sizing Props
| Prop | Type | Default | Description |
|---|---|---|---|
width | number | string | - | Player width |
height | number | string | - | Player height |
aspectRatio | '16:9' | '4:3' | '1:1' | 'auto' | '16:9' | Aspect ratio |
Controls Props
| Prop | Type | Default | Description |
|---|---|---|---|
controls | boolean | ControlElement[] | true | Control bar config |
controlsAutoHide | boolean | true | Auto-hide controls |
controlsAutoHideDelay | number | 3000 | Hide delay (ms) |
qualitySelector | boolean | true | Show quality selector |
playbackRateSelector | boolean | true | Show speed selector |
pictureInPicture | boolean | true | Enable PiP |
fullscreen | boolean | true | Enable fullscreen |
Styling Props
| Prop | Type | Default | Description |
|---|---|---|---|
theme | VideoPlayerTheme | - | Theme customization |
rounded | 'none' | 'sm' | 'md' | 'lg' | 'md' | Border radius |
className | string | - | Additional CSS classes |
Events
| Prop | Type | Description |
|---|---|---|
onReady | (player: ShakaPlayer) => void | Player ready |
onPlay | () => void | Playback started |
onPause | () => void | Playback paused |
onEnded | () => void | Playback ended |
onError | (error: Error) => void | Error occurred |
onTimeUpdate | (time: number) => void | Time update |
onProgress | (buffered: number) => void | Buffer progress |
Types
ControlElement
type ControlElement =
| "play_pause"
| "mute"
| "volume"
| "current_time"
| "duration"
| "seek_bar"
| "spacer"
| "quality"
| "playback_rate"
| "picture_in_picture"
| "fullscreen";
VideoPlayerTheme
interface VideoPlayerTheme {
primaryColor?: string; // Play button, progress bar
secondaryColor?: string; // Buffered progress
backgroundColor?: string; // Control bar background
textColor?: string; // Text/icons
seekBarHeight?: number; // Seek bar height (px)
seekBarHoverHeight?: number; // Seek bar hover height (px)
controlBarHeight?: number; // Control bar height (px)
buttonSize?: number; // Button size (px)
}
SSR Handling
The component uses dynamic import with ssr: false to avoid server-side rendering issues with Shaka Player:
// VideoPlayer.tsx - SSR-safe wrapper
"use client";
import dynamic from "next/dynamic";
import { LoadingSpinner } from "@elcto/ui";
const ShakaPlayerImpl = dynamic(() => import("./ShakaPlayer"), {
ssr: false,
loading: () => (
<div className="flex items-center justify-center bg-[var(--bg-2)] aspect-video rounded-lg">
<LoadingSpinner size="lg" />
</div>
),
});
Theming with Design Tokens
The player uses CSS variables from @elcto/ui design tokens:
.video-player-wrapper {
--vp-primary: var(--brand); /* #14f5bf */
--vp-primary-hover: var(--brand-hover); /* #12d9a8 */
--vp-bg: var(--bg-1); /* #181b21 */
--vp-text: var(--text-primary); /* #ededf3 */
--vp-border: var(--border-subtle); /* rgba(126, 130, 139, 0.2) */
--vp-error: var(--error); /* #ff5859 */
}
Override in your theme:
.video-player-wrapper {
--vp-primary: #ff6b6b;
--vp-control-height: 56px;
}