video-player

Previous

A video player component for shadcn/ui. Easily create a video player with a progress bar, volume control, and fullscreen toggle.

Docs
shadix-uicomponent

Preview

Loading preview…
registry/new-york/components/video-player/video-player.tsx
"use client";
import type React from "react";

import "@/registry/new-york/styles/video-player.css";

import { VideoPlayerBuffer } from "@/registry/new-york/components/video-player/video-player-buffer";
import { VideoPlayerControls } from "@/registry/new-york/components/video-player/video-player-controls";
import { VideoPlayerIndicator } from "@/registry/new-york/components/video-player/video-player-indicator";
import { VideoPlayerProgressBar } from "@/registry/new-york/components/video-player/video-player-progress-bar";
import { useVideoPlayer } from "@/registry/new-york/hooks/useVideoPlayer";

export interface VideoPlayerProps {
    /** @public (required) Source of the video */
    src:
        | string
        | {
              "2160p"?: string;
              "1440p"?: string;
              "1080p"?: string;
              "720p"?: string;
              "480p"?: string;
              "360p"?: string;
              "240p"?: string;
          };
    /** @public (optional) Whether to autoplay the video */
    autoPlay?: boolean;
    /** @public (optional) Thumbnail image for the video */
    thumbnail?: string;
    /** @public (optional) Time at which to display the thumbnail */
    thumbnailTime?: number;
    /** @public (optional) Subtitles for the video */
    subtitles?: {
        src: string;
        lang: string;
        label: string;
    }[];
}

const VideoPlayer: React.FC<VideoPlayerProps> = ({
    subtitles,
    src,
    autoPlay = false,
    thumbnail,
    thumbnailTime,
}) => {
    const {
        playerRef,
        containerRef,
        playing,
        indicator,
        isBuffering,
        volume,
        muted,
        progress,
        displayThumb,
        loadedProgress,
        isFullscreen,
        toggleFullscreen,
        handleProgress,
        handlePlay,
        handlePause,
        handlePlayPause,
        handleVolumeChange,
        handleWaiting,
        handleCanPlay,
        seek,
        setMuted,
    } = useVideoPlayer({
        src,
        autoPlay,
        thumbnail,
        thumbnailTime,
    });

    return (
        <div className="w-full max-w-2xl mx-auto overflow-hidden">
            <div ref={containerRef} className="relative">
                <video
                    ref={playerRef}
                    src={src as string}
                    className="w-full min-h-72 bg-muted aspect-video"
                    controls={false}
                    poster={displayThumb || undefined}
                    crossOrigin="anonymous"
                    onTimeUpdate={handleProgress}
                    onLoadedMetadata={handleProgress}
                    onPlay={handlePlay}
                    onPause={handlePause}
                    onClick={handlePlayPause}
                    onWaiting={handleWaiting}
                    onCanPlay={handleCanPlay}
                    onCanPlayThrough={handleCanPlay}
                    muted={muted}
                >
                    <track kind="captions" srcLang="en" label="English" />
                    {subtitles?.map((sub) => (
                        <track
                            key={`${sub.src}-${sub.lang}`}
                            src={sub.src}
                            kind="captions"
                            label={sub.label}
                            srcLang={sub.lang}
                        />
                    ))}
                </video>

                <VideoPlayerBuffer isBuffering={isBuffering} />

                <VideoPlayerIndicator indicator={indicator} playing={playing} />

                <VideoPlayerProgressBar
                    progress={progress}
                    loadedProgress={loadedProgress}
                    playerRef={playerRef as React.RefObject<HTMLVideoElement>}
                    duration={playerRef.current?.duration || 0}
                    onSeek={seek}
                />

                <VideoPlayerControls
                    playing={playing}
                    volume={volume}
                    muted={muted}
                    isFullscreen={isFullscreen}
                    toggleFullscreen={toggleFullscreen}
                    onPlayPause={handlePlayPause}
                    onVolumeChange={handleVolumeChange}
                    onMuteToggle={() => setMuted(!muted)}
                />
            </div>
        </div>
    );
};

export { VideoPlayer };

Installation

npx shadcn@latest add @shadix-ui/video-player

Usage

import { VideoPlayer } from "@/components/video-player"
<VideoPlayer />