Skip to main content

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

PropTypeDefaultDescription
srcstringrequiredVideo source URL (MP4, HLS, DASH)
posterstring-Poster image URL
videoIdstring-Unique ID for resume playback (defaults to src hash)

Playback Props

PropTypeDefaultDescription
autoPlaybooleanfalseAuto-start playback
mutedbooleanfalseStart muted
loopbooleanfalseLoop playback
playbackRatenumber1Playback speed
volumenumber1Volume (0-1)
startTimenumber-Start position in seconds

Resume Playback Props

PropTypeDefaultDescription
rememberPositionbooleanfalseEnable resume from last position
saveIntervalnumber5000Position save interval (ms)
resumeThresholdnumber30Seconds from end to clear saved position

Sizing Props

PropTypeDefaultDescription
widthnumber | string-Player width
heightnumber | string-Player height
aspectRatio'16:9' | '4:3' | '1:1' | 'auto''16:9'Aspect ratio

Controls Props

PropTypeDefaultDescription
controlsboolean | ControlElement[]trueControl bar config
controlsAutoHidebooleantrueAuto-hide controls
controlsAutoHideDelaynumber3000Hide delay (ms)
qualitySelectorbooleantrueShow quality selector
playbackRateSelectorbooleantrueShow speed selector
pictureInPicturebooleantrueEnable PiP
fullscreenbooleantrueEnable fullscreen

Styling Props

PropTypeDefaultDescription
themeVideoPlayerTheme-Theme customization
rounded'none' | 'sm' | 'md' | 'lg''md'Border radius
classNamestring-Additional CSS classes

Events

PropTypeDescription
onReady(player: ShakaPlayer) => voidPlayer ready
onPlay() => voidPlayback started
onPause() => voidPlayback paused
onEnded() => voidPlayback ended
onError(error: Error) => voidError occurred
onTimeUpdate(time: number) => voidTime update
onProgress(buffered: number) => voidBuffer 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;
}