useFullscreen (React)

This hook allows you to easily get access to the current fullscreen element, and control set (enter), unset (exit) and toggle the fullscreen element. Get access

typescriptjavascript
import { useCallback, useEffect, useRef, useState } from 'react'
 
type FullscreenControls = {
  enter: (element: Element, options?: FullscreenOptions) => Promise<void>
  exit: () => Promise<void>
  toggle: (element: Element, options?: FullscreenOptions) => Promise<void>
}
 
export const useFullscreen = (): [
  fullscreenElement: Element | null,
  controls: FullscreenControls
] => {
  const [fullscreenElement, setFullscreenElement] = useState<Element | null>(
    null
  )
 
  const fullscreenElementRef = useRef<Element | null>(null)
 
  useEffect(() => {
    const handler = () => {
      setFullscreenElement(document.fullscreenElement)
      fullscreenElementRef.current = document.fullscreenElement
    }
    document.addEventListener('fullscreenchange', handler)
 
    return () => {
      document.removeEventListener('fullscreenchange', handler)
    }
  }, [])
 
  const enter = useCallback<FullscreenControls['enter']>(
    async (element, options) => {
      await element.requestFullscreen(options)
    },
    []
  )
 
  const exit = useCallback<FullscreenControls['exit']>(async () => {
    if (!document.fullscreenElement) return
    await document.exitFullscreen()
  }, [])
 
  const toggle = useCallback<FullscreenControls['toggle']>(
    async (element, options) => {
      if (fullscreenElementRef.current === element) {
        await exit()
      } else {
        await enter(element, options)
      }
    },
    [enter, exit]
  )
 
  return [
    fullscreenElement,
    {
      enter,
      exit,
      toggle,
    },
  ]
}
import { useCallback, useEffect, useRef, useState } from 'react'
 
export const useFullscreen = () => {
  const [fullscreenElement, setFullscreenElement] = useState(null)
 
  const fullscreenElementRef = useRef(null)
 
  useEffect(() => {
    const handler = () => {
      setFullscreenElement(document.fullscreenElement)
      fullscreenElementRef.current = document.fullscreenElement
    }
    document.addEventListener('fullscreenchange', handler)
 
    return () => {
      document.removeEventListener('fullscreenchange', handler)
    }
  }, [])
 
  const enter = useCallback(async (element, options) => {
    await element.requestFullscreen(options)
  }, [])
 
  const exit = useCallback(async () => {
    if (!document.fullscreenElement) return
    await document.exitFullscreen()
  }, [])
 
  const toggle = useCallback(
    async (element, options) => {
      if (fullscreenElementRef.current === element) {
        await exit()
      } else {
        await enter(element, options)
      }
    },
    [enter, exit]
  )
 
  return [
    fullscreenElement,
    {
      enter,
      exit,
      toggle,
    },
  ]
}

Usage

typescriptjavascript
import { useFullscreen } from './useFullscreen'
 
const Example = () => {
  const [fullscreenElement, fullscreenControls] = useFullscreen()
 
  return (
    <div>
      <button onClick={() => fullscreenControls.enter(document.body)}>
        Enter
      </button>
      <button onClick={() => fullscreenControls.exit()}>Exit</button>
      <button onClick={() => fullscreenControls.toggle(document.body)}>
        Toggle
      </button>
    </div>
  )
}
import { useFullscreen } from './useFullscreen'
 
const Example = () => {
  const [fullscreenElement, fullscreenControls] = useFullscreen()
 
  return (
    <div>
      <button onClick={() => fullscreenControls.enter(document.body)}>
        Enter
      </button>
      <button onClick={() => fullscreenControls.exit()}>Exit</button>
      <button onClick={() => fullscreenControls.toggle(document.body)}>
        Toggle
      </button>
    </div>
  )
}

Warning

When you enter fullscreen with an element, you may notice a couple things:

  1. The fullscreen-ed element will be stretched to fill the screen, and scrolling may be disabled
  2. The background may become black

You can (and probably should, unlike me 😅) fix these issues with CSS. For example using the :fullscreen and :-webkit-full-screen pseudo-classes (postcss-preset-env can add the latter for you!) to fix the disabled scrolling:

css
*:fullscreen {
  overflow: auto;
}
 
*:-webkit-full-screen {
  overflow: auto;
}

Example

Created 14/08/23
Found a mistake, or want to suggest an improvement? Source on GitHub here
and see edit history here