Rooks
HooksUI & Layout

useVideo

Supplies a video ref with playback, timing, mute, volume, seeking, and fullscreen controls.

About

useVideo is a compact controller for one stable <video> element. It mirrors time, duration, play/pause state and exposes synchronous control functions for common media operations.

Example

import { useVideo } from "rooks";

export default function VideoPlayer() {
  const [videoRef, video, controls] = useVideo();

  return (
    <section>
      <video ref={videoRef} src="/example-video.mp4" controls width={480}>
        <track
          kind="captions"
          src="/example-captions.vtt"
          srcLang="en"
          label="English"
          default
        />
      </video>
      <p aria-live="polite">
        {video.isPaused ? "Paused" : "Playing"} at{" "}
        {Math.round(video.currentTime)} of {Math.round(video.duration)} seconds
      </p>
      <button
        type="button"
        onClick={video.isPaused ? controls.play : controls.pause}
      >
        {video.isPaused ? "Play" : "Pause"}
      </button>
      <button type="button" onClick={() => controls.rewind(10)}>
        Back 10 seconds
      </button>
      <button type="button" onClick={() => controls.fastForward(10)}>
        Forward 10 seconds
      </button>
      <button type="button" onClick={controls.toggleMute}>
        {video.isMuted ? "Unmute" : "Mute"}
      </button>
    </section>
  );
}

The media and captions paths represent assets supplied by the application.

Parameters

This hook accepts no parameters. The video source and native element properties belong on the <video> element.

Return value

Returns [videoRef, state, controls].

  • videoRef is an object ref for an HTMLVideoElement.
  • state contains currentTime and duration (initially 0), isPaused (initially true), isMuted (initially false), and volume (initially 1).
  • controls contains play, pause, toggleMute, setVolume, setCurrentTime, fastForward, rewind, and toggleFullScreen. Every control returns void.

These state and control shape names are internal and cannot be imported from rooks.

Behavior and lifecycle

After mount, the hook subscribes to timeupdate, durationchange, pause, and play on the referenced video and removes those listeners on unmount. Keep the ref attached to the same video for the hook's lifetime; changing only videoRef.current does not rerun the listener effect.

Controls do nothing while the ref is null. setVolume does not clamp its argument, and seeking helpers do not clamp time; invalid assignments follow browser behavior and can throw. play() and fullscreen methods ignore their platform promises, so this hook does not expose autoplay, permission, or fullscreen rejection errors. Native volume or mute changes are not subscribed to and can leave those two state fields stale unless the hook's controls made the change.

Compatibility and accessibility

The initial tuple is safe to render on the server, and controls are inert until a client element attaches. Playback and fullscreen generally require user activation; toggleFullScreen() also requires Fullscreen API support. Use useFullscreen when promise handling and availability state are required, or usePictureInPictureApi for PiP support and errors.

Prefer native media controls or provide equivalent keyboard operation, names, focus indication, captions, and transcripts. Do not rely only on the hook's mirrored state to report playback errors. See SSR and browser APIs.

  • useAudio offers richer callbacks, clamping, loading, buffering, rate, and error state.
  • usePictureInPictureApi manages Picture-in-Picture for the same video ref.
  • useFullscreen exposes support and promise-returning fullscreen controls.

On this page