use Fullscreen (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:
- The fullscreen-ed element will be stretched to fill the screen, and scrolling may be disabled
- 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;
}