Written by: Marlon Colca
Posted on 10 Sep 2025 - 24 days ago
nextjs typescript clones
Build a simple, robust <video> player that accepts multiple sources and optional subtitles — friendly to mobile, and easy to extend
Goal
<video>
player that accepts multiple sources and optional subtitles — friendly to mobile, and easy to extend. 🎯type Props = {
sources: { src: string; type: string; label?: string }[];
poster?: string;
subtitles?: { src: string; lang: string; label: string; default?: boolean }[];
autoPlay?: boolean;
controls?: boolean;
className?: string;
storageKey?: string; // unique id to persist position
resume?: boolean; // restore last position automatically
autoFullscreen?: boolean; // best effort to enter fullscreen on start
};
// src/components/VideoPlayer.tsx
return (
<video
className="h-full w-full rounded-md"
controls={controls}
preload="metadata"
poster={poster}
playsInline
{...(autoPlay ? { autoPlay: true, muted: true } : {})}
>
{[...sources]
.sort(
(a, b) =>
(a.type.includes("mp4") ? 0 : 1) - (b.type.includes("mp4") ? 0 : 1)
)
.map((s) => (
<source key={s.src} src={s.src} type={s.type} />
))}
{(subtitles ?? []).map((t) => (
<track
key={t.src}
src={t.src}
kind="subtitles"
srcLang={t.lang}
label={t.label}
{...(t.default ? { default: true } : {})}
/>
))}
Your browser does not support the video tag.
</video>
);
<VideoPlayer
sources={[
{ src: "/videos/sample-720p.mp4", type: "video/mp4", label: "720p" },
{ src: "/videos/sample-480p.webm", type: "video/webm", label: "480p" },
]}
subtitles={[
{ src: "/subs/sample-en.vtt", lang: "en", label: "English", default: true },
]}
poster="/posters/sample.jpg"
controls
/>
preload="metadata"
and playsInline
for mobile.<video>
first 💡<source>
, posters, and text tracks.playsInline
avoids forced fullscreen on iOS Safari, keeping UX consistent with overlays.muted
; we apply it automatically when autoPlay
is set.controls
and test keyboard controls from Part 09 once added.Add support for .srt subtitles by converting them to WebVTT on the fly, so the native browser player can render captions without extra tooling.
11 Sep 2025 - 23 days ago