Files
v10/packages/react/react-media-elements/README.md
T
2025-10-21 14:02:10 -07:00

10 KiB

@vjs-10/react-media-elements

React components, hooks, and utilities for media elements

npm

Status: Early Development

⚠️ PROTOTYPE - SUBJECT TO CHANGE

This package is in early prototype phase. Expect significant changes including:

  • Package restructuring and naming
  • Breaking API changes
  • Major architectural updates
  • Incomplete or experimental features

Not recommended for production use.

Overview

@vjs-10/react-media-elements provides React-specific components and hooks for working with media elements. It offers enhanced video and audio components with built-in support for HLS/DASH streaming, along with hooks for programmatic media control.

Key Features

  • React Components - Enhanced <Video> and <Audio> components
  • React Hooks - Hooks for media state and control
  • HLS/DASH Support - Built-in streaming protocol support
  • Type Safe - Full TypeScript support with React types
  • Server-Side Safe - Works with SSR (Next.js, Remix, etc.)
  • Ref Support - Access underlying media elements via refs

Installation

npm install @vjs-10/react-media-elements

Peer Dependencies:

  • react >=16.8.0

Quick Start

Basic Video Component

import { Video } from '@vjs-10/react-media-elements';

function MyPlayer() {
  return (
    <Video
      src="video.mp4"
      poster="poster.jpg"
      controls
      autoPlay={false}
      muted={false}
    />
  );
}

HLS Streaming

import { Video } from '@vjs-10/react-media-elements';

function StreamingPlayer() {
  return (
    <Video
      src="https://example.com/stream.m3u8"
      controls
      autoPlay
      muted
    />
  );
}

With Ref

import { MediaElementVideo, Video } from '@vjs-10/react-media-elements';
import { useRef } from 'react';

function ControlledPlayer() {
  const videoRef = useRef<MediaElementVideo>(null);

  const handlePlay = () => {
    videoRef.current?.play();
  };

  const handlePause = () => {
    videoRef.current?.pause();
  };

  return (
    <div>
      <Video ref={videoRef} src="video.mp4" />
      <button onClick={handlePlay}>Play</button>
      <button onClick={handlePause}>Pause</button>
    </div>
  );
}

Components

Video

Enhanced video component with streaming support:

import { Video } from '@vjs-10/react-media-elements';

<Video
  // Source
  src="video.mp4"
  poster="poster.jpg"

  // Playback
  controls
  autoPlay={false}
  loop={false}
  muted={false}
  playsInline

  // Loading
  preload="metadata" // 'none' | 'metadata' | 'auto'

  // Styling
  className="my-video"
  style={{ width: '100%' }}

  // Events
  onPlay={() => console.log('Playing')}
  onPause={() => console.log('Paused')}
  onTimeUpdate={e => console.log('Time:', e.currentTarget.currentTime)}
  onEnded={() => console.log('Ended')}

  // Ref
  ref={videoRef}
/>;

Audio

Enhanced audio component:

import { Audio } from '@vjs-10/react-media-elements';

<Audio
  src="audio.mp3"
  controls
  autoPlay={false}
  onPlay={() => console.log('Playing')}
/>;

Hooks

useMediaElement

Hook for controlling media elements:

import { useMediaElement, Video } from '@vjs-10/react-media-elements';
import { useRef } from 'react';

function Player() {
  const videoRef = useRef<HTMLVideoElement>(null);
  const media = useMediaElement(videoRef);

  return (
    <div>
      <Video ref={videoRef} src="video.mp4" />

      <button onClick={media.play}>Play</button>
      <button onClick={media.pause}>Pause</button>
      <button onClick={() => media.seek(30)}>Seek to 30s</button>
      <button onClick={() => media.setVolume(0.5)}>50% Volume</button>

      <div>
        Current Time:
        {' '}
        {media.currentTime}
        Duration:
        {' '}
        {media.duration}
        Paused:
        {' '}
        {media.paused ? 'Yes' : 'No'}
      </div>
    </div>
  );
}

useVideoState

Hook for reactive video state:

import { useVideoState, Video } from '@vjs-10/react-media-elements';
import { useRef } from 'react';

function Player() {
  const videoRef = useRef<HTMLVideoElement>(null);
  const state = useVideoState(videoRef);

  return (
    <div>
      <Video ref={videoRef} src="video.mp4" />

      <div>
        <p>
          Current Time:
          {state.currentTime.toFixed(2)}
          s
        </p>
        <p>
          Duration:
          {state.duration.toFixed(2)}
          s
        </p>
        <p>
          Volume:
          {(state.volume * 100).toFixed(0)}
          %
        </p>
        <p>
          Status:
          {state.paused ? 'Paused' : 'Playing'}
        </p>
        <p>
          Muted:
          {state.muted ? 'Yes' : 'No'}
        </p>
      </div>
    </div>
  );
}

usePlaybackEngine

Hook for controlling HLS/DASH engines:

import { usePlaybackEngine, Video } from '@vjs-10/react-media-elements';
import { useEffect, useRef } from 'react';

function StreamingPlayer() {
  const videoRef = useRef<HTMLVideoElement>(null);
  const engine = usePlaybackEngine(videoRef, 'hls');

  useEffect(() => {
    if (engine) {
      // Configure HLS.js instance
      engine.config.debug = false;
      engine.config.lowLatencyMode = true;
    }
  }, [engine]);

  return <Video ref={videoRef} src="stream.m3u8" />;
}

Advanced Usage

Programmatic Control

import { MediaElementVideo, Video } from '@vjs-10/react-media-elements';
import { useRef } from 'react';

function AdvancedPlayer() {
  const videoRef = useRef<MediaElementVideo>(null);

  const controls = {
    play: () => videoRef.current?.play(),
    pause: () => videoRef.current?.pause(),
    seek: (time: number) => {
      if (videoRef.current) {
        videoRef.current.currentTime = time;
      }
    },
    setVolume: (volume: number) => {
      if (videoRef.current) {
        videoRef.current.volume = volume;
      }
    },
    toggleMute: () => {
      if (videoRef.current) {
        videoRef.current.muted = !videoRef.current.muted;
      }
    },
    setSpeed: (rate: number) => {
      if (videoRef.current) {
        videoRef.current.playbackRate = rate;
      }
    },
  };

  return (
    <div>
      <Video ref={videoRef} src="video.mp4" />
      <div className="controls">
        <button onClick={controls.play}>Play</button>
        <button onClick={controls.pause}>Pause</button>
        <button onClick={() => controls.seek(30)}>Skip to 30s</button>
        <button onClick={() => controls.setVolume(0.5)}>50% Volume</button>
        <button onClick={controls.toggleMute}>Toggle Mute</button>
        <button onClick={() => controls.setSpeed(1.5)}>1.5x Speed</button>
      </div>
    </div>
  );
}

Event Handling

import { Video } from '@vjs-10/react-media-elements';
import { useState } from 'react';

function EventPlayer() {
  const [status, setStatus] = useState('Ready');

  return (
    <div>
      <Video
        src="video.mp4"
        onLoadStart={() => setStatus('Loading...')}
        onLoadedMetadata={() => setStatus('Metadata loaded')}
        onCanPlay={() => setStatus('Can play')}
        onPlay={() => setStatus('Playing')}
        onPause={() => setStatus('Paused')}
        onEnded={() => setStatus('Ended')}
        onError={e => setStatus(`Error: ${e.message}`)}
        onWaiting={() => setStatus('Buffering...')}
        onStalled={() => setStatus('Stalled')}
      />
      <div>
        Status:
        {status}
      </div>
    </div>
  );
}

Source Switching

import { Video } from '@vjs-10/react-media-elements';
import { useState } from 'react';

function MultiSourcePlayer() {
  const sources = [
    { url: 'video1.mp4', title: 'Video 1' },
    { url: 'video2.mp4', title: 'Video 2' },
    { url: 'stream.m3u8', title: 'HLS Stream' },
  ];

  const [currentSource, setCurrentSource] = useState(0);

  return (
    <div>
      <Video src={sources[currentSource].url} controls />

      <div className="playlist">
        {sources.map((source, index) => (
          <button
            key={index}
            onClick={() => setCurrentSource(index)}
            disabled={index === currentSource}
          >
            {source.title}
          </button>
        ))}
      </div>
    </div>
  );
}

With Media Store

import { Video } from '@vjs-10/react-media-elements';
import { useMediaStore } from '@vjs-10/react-media-store';

function StoreIntegratedPlayer() {
  const store = useMediaStore();

  return (
    <div>
      <Video src="video.mp4" store={store} />

      {/* Other components can access the same store */}
      <CustomControls store={store} />
      <ProgressBar store={store} />
    </div>
  );
}

TypeScript Support

Full TypeScript definitions included:

import type {
  AudioProps,
  MediaElementAudio,
  MediaElementState,
  MediaElementVideo,
  VideoProps,
} from '@vjs-10/react-media-elements';

// Component props
const videoProps: VideoProps = {
  src: 'video.mp4',
  controls: true,
  autoPlay: false,
};

// Element ref types
const videoRef = useRef<MediaElementVideo>(null);
const audioRef = useRef<MediaElementAudio>(null);

Server-Side Rendering

Components are SSR-safe and work with Next.js, Remix, etc:

// Works in Next.js App Router
import { Video } from '@vjs-10/react-media-elements';

export default function Page() {
  return <Video src="video.mp4" controls />;
}

Package Dependencies

  • Dependencies:
    • @vjs-10/media - Media utilities
    • @vjs-10/playback-engine - Streaming engines
  • Peer Dependencies:
    • react >=16.8.0
  • Used by: @vjs-10/react - Complete React player

Development

# Build the package
pnpm build

# Watch mode for development
pnpm dev

# Run tests
pnpm test

# Clean build artifacts
pnpm clean

License

Apache-2.0