An HTML5 video player that supports HLS and DASH with a common API and skin.
—
Video.js provides an extensible plugin architecture that allows developers to add custom functionality to players through both function-based and class-based plugins.
Register plugins with Video.js for use across all player instances or specific players.
/**
* Register a plugin with Video.js
* @param name - Plugin name (used to invoke plugin)
* @param plugin - Plugin function or class
* @returns Registered plugin
*/
videojs.registerPlugin<T = Plugin>(name: string, plugin: PluginFunction<T> | typeof Plugin): PluginFunction<T> | typeof Plugin;
/**
* Remove registered plugin
* @param name - Plugin name to deregister
*/
videojs.deregisterPlugin(name: string): void;
/**
* Get registered plugin by name
* @param name - Plugin name
* @returns Plugin function or class
*/
videojs.getPlugin(name: string): PluginFunction | typeof Plugin | undefined;
/**
* Get all registered plugins
* @returns Object with all registered plugins
*/
videojs.getPlugins(): Record<string, PluginFunction | typeof Plugin>;
/**
* Get version of registered plugin
* @param name - Plugin name
* @returns Plugin version string
*/
videojs.getPluginVersion(name: string): string;Usage Examples:
// Register function-based plugin
videojs.registerPlugin('logger', function(options) {
this.on('play', () => console.log('Player started'));
this.on('pause', () => console.log('Player paused'));
});
// Register class-based plugin
class AnalyticsPlugin extends videojs.getComponent('Plugin') {
constructor(player, options) {
super(player, options);
this.setupAnalytics();
}
setupAnalytics() {
this.player.on('play', this.trackPlay.bind(this));
}
trackPlay() {
// Send analytics event
}
}
videojs.registerPlugin('analytics', AnalyticsPlugin);
// Use plugins
const player = videojs('my-video');
player.logger(); // Initialize logger plugin
player.analytics({ trackingId: 'UA-12345' }); // Initialize with optionsSimple plugins that add functionality through functions attached to player instances.
/**
* Function-based plugin signature
* @param options - Plugin options passed during initialization
*/
type PluginFunction<T = any> = (this: Player, options?: T) => void;Usage Examples:
// Simple function plugin
videojs.registerPlugin('skipIntro', function(options = {}) {
const skipTime = options.skipTime || 10;
// Add skip button
const skipButton = this.addChild('button', {
text: 'Skip Intro'
});
skipButton.on('click', () => {
this.currentTime(skipTime);
skipButton.hide();
});
// Auto-hide after intro
this.on('timeupdate', () => {
if (this.currentTime() > skipTime) {
skipButton.hide();
}
});
});
// Use the plugin
player.skipIntro({ skipTime: 15 });Advanced plugins using classes that extend the base Plugin class for complex functionality.
/**
* Base Plugin class for class-based plugins
*/
class Plugin {
/**
* Create plugin instance
* @param player - Player instance
* @param options - Plugin options
*/
constructor(player: Player, options?: object);
/**
* Associated player instance
*/
readonly player: Player;
/**
* Plugin options
*/
readonly options: object;
/**
* Dispose plugin and clean up resources
*/
dispose(): void;
/**
* Check if plugin has been disposed
* @returns True if disposed
*/
isDisposed(): boolean;
/**
* Execute callback when plugin is ready
* @param callback - Function to call when ready
*/
ready(callback: () => void): void;
}Usage Examples:
// Advanced class-based plugin
class PlaylistPlugin extends videojs.getComponent('Plugin') {
constructor(player, options) {
super(player, options);
this.playlist = options.playlist || [];
this.currentIndex = 0;
this.setupPlaylist();
}
setupPlaylist() {
// Add playlist UI
this.playlistMenu = this.player.addChild('MenuButton', {
label: 'Playlist'
});
// Handle video end
this.player.on('ended', this.playNext.bind(this));
// Load first video
if (this.playlist.length > 0) {
this.loadVideo(0);
}
}
loadVideo(index) {
if (index >= 0 && index < this.playlist.length) {
this.currentIndex = index;
const video = this.playlist[index];
this.player.src(video.src);
this.player.poster(video.poster);
}
}
playNext() {
const nextIndex = (this.currentIndex + 1) % this.playlist.length;
this.loadVideo(nextIndex);
this.player.play();
}
playPrevious() {
const prevIndex = this.currentIndex === 0
? this.playlist.length - 1
: this.currentIndex - 1;
this.loadVideo(prevIndex);
this.player.play();
}
dispose() {
this.playlistMenu.dispose();
super.dispose();
}
}
// Register and use
videojs.registerPlugin('playlist', PlaylistPlugin);
const player = videojs('my-video');
player.playlist({
playlist: [
{ src: 'video1.mp4', poster: 'poster1.jpg', title: 'Video 1' },
{ src: 'video2.mp4', poster: 'poster2.jpg', title: 'Video 2' }
]
});Plugins have built-in state management and lifecycle hooks.
/**
* Get plugin state for a player
* @param player - Player instance
* @param name - Plugin name
* @returns Plugin state object
*/
videojs.getPluginState(player: Player, name: string): PluginState;
/**
* Set plugin state for a player
* @param player - Player instance
* @param name - Plugin name
* @param state - State to set
*/
videojs.setPluginState(player: Player, name: string, state: PluginState): void;Plugins can accept configuration options and provide default values.
// Plugin with default options
videojs.registerPlugin('customPlayer', function(options) {
const settings = videojs.obj.merge({
theme: 'default',
showProgress: true,
autoHide: 3000
}, options);
// Apply theme
this.addClass(`vjs-theme-${settings.theme}`);
// Configure progress bar
if (!settings.showProgress) {
this.getChild('ControlBar').getChild('ProgressControl').hide();
}
// Auto-hide controls
let hideTimeout;
this.on('mousemove', () => {
this.removeClass('vjs-user-inactive');
clearTimeout(hideTimeout);
hideTimeout = setTimeout(() => {
this.addClass('vjs-user-inactive');
}, settings.autoHide);
});
});Plugins can extend other plugins to build upon existing functionality.
// Base analytics plugin
class BaseAnalytics extends videojs.getComponent('Plugin') {
constructor(player, options) {
super(player, options);
this.events = [];
}
track(event, data) {
this.events.push({ event, data, timestamp: Date.now() });
console.log('Tracking:', event, data);
}
}
// Google Analytics plugin extending base
class GoogleAnalytics extends BaseAnalytics {
constructor(player, options) {
super(player, options);
this.trackingId = options.trackingId;
this.setupGA();
}
setupGA() {
// Initialize Google Analytics
this.player.on('play', () => this.track('video_play'));
this.player.on('pause', () => this.track('video_pause'));
this.player.on('ended', () => this.track('video_complete'));
}
track(event, data) {
super.track(event, data);
// Send to Google Analytics
if (window.gtag) {
window.gtag('event', event, {
video_title: this.player.poster() || 'Unknown',
...data
});
}
}
}
videojs.registerPlugin('googleAnalytics', GoogleAnalytics);Video.js maintains backward compatibility with older plugin patterns.
/**
* Legacy plugin registration method (deprecated)
* @param name - Plugin name
* @param plugin - Plugin function or class
* @returns Registered plugin
* @deprecated Use videojs.registerPlugin() instead
*/
videojs.plugin(name: string, plugin: PluginFunction | typeof Plugin): PluginFunction | typeof Plugin;interface Plugin {
player: Player;
options: object;
dispose(): void;
isDisposed(): boolean;
ready(callback: () => void): void;
}
type PluginFunction<T = any> = (this: Player, options?: T) => void;
interface PluginState {
[key: string]: any;
}
interface PluginOptions {
[key: string]: any;
}
// Plugin lifecycle hooks
interface PluginLifecycle {
beforePluginSetup?: (player: Player, options: object) => void;
afterPluginSetup?: (player: Player, plugin: Plugin) => void;
}Install with Tessl CLI
npx tessl i tessl/npm-video-js