lazyvid
v1.0.0
Published
React lazy video component that lazy-loads HTML5 video sources with IntersectionObserver
Downloads
142
Maintainers
Readme
lazyvid - React lazy video component
Lazy-load HTML5 <video> sources in React with predictable behavior.
lazyvid renders an empty <video> element and injects <source> tags only when the element enters the viewport.
Until then — nothing downloads.
It relies on IntersectionObserver for visibility tracking and lets the browser handle native format selection (webm, mp4, etc).
Use it for React lazy video, HTML5 video lazy loading, background videos, hero videos, and media-heavy pages where video should not download before it is visible.
~2 KB (ESM bundle). Zero dependencies. Full TypeScript support.
<LazyVideo
sources={[
{ src: "/hero.webm", type: "video/webm" },
{ src: "/hero.mp4", type: "video/mp4" },
]}
muted
autoPlay
loop
/>Single component. No additional setup.
Release status
lazyvid is officially released as 1.0.0.
The test suite passes, so the package is ready for stable use.
Why?
Browsers start fetching <video> sources as soon as <source> elements are present in the DOM.
On media-heavy pages, this means unnecessary bandwidth usage and background CPU activity — even if the user never scrolls to the video.
lazyvid avoids that by delaying source injection until the element becomes visible (with configurable preload offset).
- No user-agent checks.
- No format guessing.
The browser still decides which source to play.
What it does
- Renders an empty
<video> - Observes it with IntersectionObserver
- Injects
<source>elements when it enters the viewport - Optionally pauses playback when it leaves
That’s it.
Install
npm install lazyvidRequires React 18 or 19.
Usage
Basic — just lazy load it
import { LazyVideo } from "lazyvid";
<LazyVideo
sources={[
{ src: "/promo.webm", type: "video/webm" },
{ src: "/promo.mp4", type: "video/mp4" },
]}
poster="/promo-poster.jpg"
controls
/>;Sources are listed in priority order. The browser takes the first format it supports — put your lightest format first.
Background video that pauses off-screen
<LazyVideo
sources={[
{ src: "/bg.webm", type: "video/webm" },
{ src: "/bg.mp4", type: "video/mp4" },
]}
poster="/bg-poster.jpg"
autoPlay
muted
loop
pauseOnLeave
style={{ width: "100%", objectFit: "cover" }}
/>When the user scrolls away — video pauses. Scrolls back — resumes. No wasted CPU on invisible playback.
onLoaded — trigger actions when video enters viewport
onLoaded fires once, when the video enters the viewport, <source> elements are injected, and loading starts. It does not fire when loading is complete — use onCanPlay for that.
This allows you to build logic on top of it, for example:
- start animations or UI effects
- show captions or overlays
- preload next section, next video, or related data
- track engagement: the user reached this video
<div style={{ position: "relative" }}>
<LazyVideo
sources={[{ src: "/intro.mp4", type: "video/mp4" }]}
poster="/intro-thumb.jpg"
controls
onLoaded={() => {
console.log("Video entered viewport, loading started!");
// trigger animations, preload next content, track engagement...
}}
/>
</div>Start loading earlier
By default, loading starts 200px before the video is visible. Want more buffer?
<LazyVideo
sources={[{ src: "/hero.mp4", type: "video/mp4" }]}
rootMargin="500px"
muted
autoPlay
/>Props
| Prop | Type | Default | Description |
| -------------- | --------------------- | --------- | ----------------------------------------------- |
| sources | VideoSource[] | required | { src, type } objects in priority order |
| threshold | number | 0 | How much of the element should be visible (0–1) |
| rootMargin | string | "200px" | Start loading before the element is in view |
| pauseOnLeave | boolean | false | Pause when out of viewport, resume when back |
| onLoaded | () => void | — | Fires when sources are injected |
| ...rest | VideoHTMLAttributes | — | Any native <video> attribute works |
How it works
- Renders an empty
<video>— nothing downloads - IntersectionObserver watches it (with
rootMarginfor early preloading) - Element enters viewport →
<source>tags injected → browser picks best format → loading starts - Observer disconnects (one-time job)
- If
pauseOnLeaveis on, a second observer manages play/pause on scroll
Types
import { LazyVideo, type VideoSource } from "lazyvid";License
MIT
