Skip to content

GuidePlayback

Add a background video

Add an accessible background video from an MP4, WebM, HLS, or Mux source

Add a decorative video behind your page content. Start with an MP4 or WebM file, which browsers can play directly. If your video is delivered as HLS, use the HLS or Mux option below.

Use BackgroundVideo with an MP4 or WebM URL. Put the video and poster inside a wrapper with aria-hidden="true" because both are decorative. Keep the heading, links, and other page content outside that wrapper.

Build the next great video experience

Compare source options
import { BackgroundVideo } from '@videojs/react/media/background-video';
import { useEffect, useRef, useState } from 'react';

export default function BasicUsage() {
  const videoRef = useRef<HTMLVideoElement>(null);
  const [motionEnabled, setMotionEnabled] = useState(false);

  useEffect(() => {
    const preference = window.matchMedia('(prefers-reduced-motion: reduce)');
    const syncPreference = () => setMotionEnabled(!preference.matches);

    syncPreference();
    preference.addEventListener('change', syncPreference);

    return () => preference.removeEventListener('change', syncPreference);
  }, []);

  useEffect(() => {
    const video = videoRef.current;
    if (!video) return;

    let cancelled = false;

    if (motionEnabled) {
      video.play().catch(() => {
        if (!cancelled) setMotionEnabled(false);
      });
    } else {
      video.pause();
    }

    return () => {
      cancelled = true;
    };
  }, [motionEnabled]);

  return (
    <section className="add-background-video-react-demo" data-motion-enabled={motionEnabled ? '' : undefined}>
      <div className="add-background-video-react-demo__visual" aria-hidden="true">
        <img className="add-background-video-react-demo__poster" src="https://image.mux.com/601n4w1fq88NJiVpzvrQQeQfNnnjjfKMIN7dCGAEarTs/thumbnail.webp" alt="" />
        <BackgroundVideo
          ref={videoRef}
          className="add-background-video-react-demo__media"
          src="https://stream.mux.com/601n4w1fq88NJiVpzvrQQeQfNnnjjfKMIN7dCGAEarTs/highest.mp4"
          autoPlay={false}
        />
      </div>
      <div className="add-background-video-react-demo__content">
        <h3>Build the next great video experience</h3>
        <a href="#common-variations">Compare source options</a>
        <button
          type="button"
          className="add-background-video-react-demo__motion-toggle"
          onClick={() => setMotionEnabled((enabled) => !enabled)}
        >
          {motionEnabled ? 'Hide background motion' : 'Show background motion'}
        </button>
      </div>
    </section>
  );
}

How it works

BackgroundVideo renders a native <video> with muted, looping, inline playback. The example disables its default autoplay with autoPlay={false} and starts playback after checking the motion preference. The decorative wrapper contains the video and an empty-alt poster; it is hidden from assistive technology and ignores pointer input.

The page defines the hero’s size. The video fills that space with --media-object-fit: cover, while the poster stays behind it. The motion button pauses and hides the video, revealing the poster. It sits outside the decorative wrapper so keyboard and screen-reader users can operate it.

When prefers-reduced-motion is active, the script pauses playback and the CSS hides the video and motion button. CSS hiding alone does not stop playback. If the browser rejects play(), the example keeps the poster visible.

Set size, position, and transforms on the decorative wrapper so the poster and video stay together.

Availability and constraints

  • Use a source the browser can play directly, such as MP4 or WebM.
  • Safari can play HLS URLs directly. Other browsers cannot do so reliably, so use an HLS variation below when the same .m3u8 URL must work across browsers.
  • BackgroundVideo does not create a poster or report analytics. Keep the poster in your page and add analytics only when you need them.
  • Provide a way to pause or hide persistent background motion. The example includes that control and follows prefers-reduced-motion. For the streaming variations below, stop and restart motion by mounting and unmounting the video.
  • If the video communicates information, remove aria-hidden, give it an accessible name and controls, and use a regular video player.

Common variations

Choose a variation based on the source you already have:

Need Use
Cross-browser HLS with a small background-only player HlsBackgroundVideo
The same background-only player for a Mux HLS URL MuxBackgroundVideo

These streaming background components always autoplay. They ignore autoPlay={false} and noautoplay.

Keep the poster and motion button from the primary example. Render the streaming component only while motionEnabled is true, and remove the native video’s play()/pause() effect. Unmounting the component stops playback; mounting it again restarts the stream.

Play an HLS video

HlsBackgroundVideo plays an HLS video without adding controls, audio, or captions. Pass a complete HLS URL through src:

pnpm add @videojs/react @videojs/spf
import { HlsBackgroundVideo } from '@videojs/react/media/hls-background-video';

<HlsBackgroundVideo
  className="hero-media"
  src="https://media.example.com/hero.m3u8"
  crossOrigin="anonymous"
  onError={() => console.error('The background stream could not play')}
/>

Your HLS stream must be unencrypted and use fragmented MP4 video segments, also called fMP4 or CMAF. The component chooses one video size when playback starts and does not switch sizes later. It cannot play older MPEG-TS segments.

Play a Mux HLS URL

MuxBackgroundVideo is a Mux-named alias for HlsBackgroundVideo. Pass a complete Mux HLS URL, not a bare playback ID or source object:

It uses the same @videojs/spf installation shown for HlsBackgroundVideo above.

import { MuxBackgroundVideo } from '@videojs/react/media/mux-background-video';

<MuxBackgroundVideo
  className="hero-media"
  src="https://stream.mux.com/PLAYBACK_ID.m3u8?max_resolution=720p"
  crossOrigin="anonymous"
/>

This component does not create a Mux poster, preview thumbnails, or analytics session. Keep the poster in your page and add analytics separately when you need them.

Troubleshooting

An HLS URL works in Safari but not another browser

BackgroundVideo hands its src to the browser’s <video> element. Use HlsBackgroundVideo for a supported fMP4 HLS source, or MuxBackgroundVideo for a Mux HLS URL.

The video does not fill or follow transforms

Set the size, transforms, and measurements on the wrapper that contains the video and poster. Size the background-video component to fill that wrapper.

No poster or Mux analytics appear

The background-video components do not provide them. Render an empty-alt poster in the same wrapper as the video, and add analytics separately.

Components

Guides