30% offEnding soon
useFullscreenLoading saved progress…

useFullscreen

The Fullscreen API lets an element occupy the entire display, while document.fullscreenElement identifies the element that is actually fullscreen. Build a React hook that controls one referenced element and stays synchronized when the browser, the user, or another part of the page changes fullscreen state.

Signature

function useFullscreen(targetRef: React.RefObject<Element | null>): {
  isFullscreen: boolean;
  enter: () => Promise<void>;
  exit: () => Promise<void>;
  toggle: () => Promise<void>;
};

Examples

function VideoPlayer() {
  const playerRef = useRef(null);
  const { isFullscreen, toggle } = useFullscreen(playerRef);

  return (
    <section ref={playerRef}>
      <video src="/trailer.mp4" />
      <button onClick={() => toggle()}>
        {isFullscreen ? 'Leave fullscreen' : 'Enter fullscreen'}
      </button>
    </section>
  );
}
await enter();  // resolves after targetRef.current.requestFullscreen()
await exit();   // resolves immediately if nothing is fullscreen

Notes

  • Derive state from the document. isFullscreen is true only when document.fullscreenElement === targetRef.current. A different fullscreen element does not count.
  • Return promises. enter, exit, and toggle are async functions that resolve with undefined after their requested work finishes.
  • Reject unsupported operations clearly. enter rejects with an Error when there is no target or it lacks requestFullscreen. While something is fullscreen, exit rejects with an Error if document.exitFullscreen is unavailable.
  • Treat an empty exit as a no-op. When document.fullscreenElement is null, exit() resolves without calling the browser API.
  • Toggle this target. Exit when this target is active; otherwise enter this target, even if another element is currently fullscreen.
  • Follow browser events. Subscribe once to document's fullscreenchange event, read document.fullscreenElement in the handler, and remove that exact listener on unmount. Do not set state optimistically just because an API promise resolves.
  • Vendor-prefixed legacy fullscreen APIs, keyboard handling, and fullscreen styling are out of scope.