Recently, I was working on a React project that required certain elements to toggle fullscreen mode, and I needed to reuse this functionality across different components. I wanted a clean, reusable solution that leveraged TypeScript to ensure type safety. This led me to create a custom hook for managing fullscreen behavior in React. In this post, I’ll walk through how I built a useFullscreen
hook, which allows you to toggle fullscreen mode on any element, all while keeping the logic clean and reusable.
Thank me by sharing on Twitter 🙏
Why Use a Custom Fullscreen Hook?
React hooks are a powerful way to abstract and reuse logic. If you’re working on a web app where fullscreen functionality is required for multiple components—whether it’s an image gallery, video player, or custom modal—using a custom hook can save time and simplify your codebase.
In this guide, we’ll focus on building a useFullscreen
hook from scratch, allowing you to toggle fullscreen mode for any element while handling browser compatibility and managing fullscreen state efficiently.
Setting Up the useFullscreen
Hook
To start, we need to create a hook that encapsulates the logic for requesting and exiting fullscreen mode. Since browsers implement fullscreen functionality differently, we’ll handle compatibility for Safari and Internet Explorer, which use vendor-prefixed methods like webkitRequestFullscreen
and msRequestFullscreen
.
We’ll also track whether the current element is in fullscreen mode and update this state when the user enters or exits fullscreen.
The World of Minecraft
$24.97 (as of December 21, 2024 19:39 GMT +00:00 - More infoProduct prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on [relevant Amazon Site(s), as applicable] at the time of purchase will apply to the purchase of this product.)The Art and Making of Arcane (Gaming)
$56.94 (as of December 21, 2024 19:39 GMT +00:00 - More infoProduct prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on [relevant Amazon Site(s), as applicable] at the time of purchase will apply to the purchase of this product.)Super Mario 2025 Wall Calendar
$11.60 (as of December 21, 2024 19:39 GMT +00:00 - More infoProduct prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on [relevant Amazon Site(s), as applicable] at the time of purchase will apply to the purchase of this product.)1. Creating the Hook Structure
First, let’s create a basic structure for the hook. We’ll use TypeScript, which ensures type safety and prevents potential runtime errors. In TypeScript, we can use the useRef
hook to track the element we want to make fullscreen, and we’ll store the fullscreen state with the useState
hook.
Here’s the initial setup:
import { useRef, useCallback, useState, useEffect } from "react";
const useFullscreen = () => {
const fullscreenRef = useRef<HTMLDivElement>(null);
const [isFullscreen, setIsFullscreen] = useState(false);
const toggleFullscreen = useCallback(() => {
if (fullscreenRef.current) {
const element = fullscreenRef.current as HTMLElement & {
webkitRequestFullscreen?: () => Promise<void>;
};
const doc = document as Document & {
webkitExitFullscreen?: () => Promise<void>;
};
if (!document.fullscreenElement) {
if (element.requestFullscreen) {
element.requestFullscreen();
} else if (element.webkitRequestFullscreen) {
element.webkitRequestFullscreen();
}
} else {
if (doc.exitFullscreen) {
doc.exitFullscreen();
} else if (doc.webkitExitFullscreen) {
doc.webkitExitFullscreen();
} else if (doc.msExitFullscreen) {
doc.msExitFullscreen();
}
}
}
}, []);
useEffect(() => {
const handleFullscreenChange = () => {
setIsFullscreen(Boolean(document.fullscreenElement));
};
document.addEventListener("fullscreenchange", handleFullscreenChange);
document.addEventListener("webkitfullscreenchange", handleFullscreenChange);
return () => {
document.removeEventListener("fullscreenchange", handleFullscreenChange);
document.removeEventListener("webkitfullscreenchange", handleFullscreenChange);
};
}, []);
return [fullscreenRef, toggleFullscreen, isFullscreen] as [
React.RefObject<HTMLDivElement>,
() => void,
boolean
];
};
export default useFullscreen;
2. Tracking Fullscreen State
One of the challenges when working with fullscreen APIs is tracking whether the element is actually in fullscreen mode. The document.fullscreenElement
property is our solution. This property returns the element currently being displayed in fullscreen mode, or null
if no element is fullscreen.
To make sure the fullscreen state is always up-to-date, we add an event listener for the fullscreenchange
event. This event fires whenever the document enters or exits fullscreen mode. Additionally, for compatibility with older browsers, we also listen to webkitfullscreenchange
(Safari) and msfullscreenchange
(Internet Explorer).
Inside the useEffect
hook, we listen for these events and update the state accordingly:
useEffect(() => {
const handleFullscreenChange = () => {
setIsFullscreen(Boolean(document.fullscreenElement));
};
document.addEventListener("fullscreenchange", handleFullscreenChange);
document.addEventListener("webkitfullscreenchange", handleFullscreenChange);
return () => {
document.removeEventListener("fullscreenchange", handleFullscreenChange);
document.removeEventListener("webkitfullscreenchange", handleFullscreenChange);
};
}, []);
This ensures that the isFullscreen
state is updated whenever the user enters or exits fullscreen mode, allowing us to control UI elements based on the current fullscreen status.
3. Handling Browser Compatibility
Different browsers implement the Fullscreen API with slight variations. Safari, for example, uses the webkitRequestFullscreen
method. Similarly, exiting fullscreen also requires different methods (webkitExitFullscreen
).
In the toggleFullscreen
function, we first check if the browser supports the standard requestFullscreen
and exitFullscreen
methods. If not, we fall back to the vendor-prefixed methods for Safari and Internet Explorer:
const element = fullscreenRef.current as HTMLElement & {
webkitRequestFullscreen?: () => Promise<void>;
msRequestFullscreen?: () => Promise<void>;
};
const doc = document as Document & {
webkitExitFullscreen?: () => Promise<void>;
msExitFullscreen?: () => Promise<void>;
};
if (!document.fullscreenElement) {
if (element.requestFullscreen) {
element.requestFullscreen();
} else if (element.webkitRequestFullscreen) {
element.webkitRequestFullscreen();
} else if (element.msRequestFullscreen) {
element.msRequestFullscreen();
}
} else {
if (doc.exitFullscreen) {
doc.exitFullscreen();
} else if (doc.webkitExitFullscreen) {
doc.webkitExitFullscreen();
} else if (doc.msExitFullscreen) {
doc.msExitFullscreen();
}
}
By checking for these methods before calling them, we ensure compatibility across most modern browsers while maintaining clean and reusable logic.
4. Reusing the Hook in Components
Now that we’ve built the hook, let’s see how we can use it in a component. By simply calling useFullscreen
, we can enable fullscreen functionality on any div
, video
, or other elements.
Here’s an example of how to use it:
import React from "react";
import useFullscreen from "./useFullscreen";
const FullscreenDiv = () => {
const [fullscreenRef, toggleFullscreen, isFullscreen] = useFullscreen();
return (
<div>
<div
ref={fullscreenRef}
style={{
width: "300px",
height: "200px",
backgroundColor: isFullscreen ? "lightblue" : "lightgreen",
textAlign: "center",
lineHeight: "200px",
margin: "20px auto",
}}
>
{isFullscreen ? "You are in fullscreen mode!" : "This is the div"}
</div>
<button onClick={toggleFullscreen}>
{isFullscreen ? "Exit Fullscreen" : "Go Fullscreen"}
</button>
</div>
);
};
export default FullscreenDiv;
This simple component demonstrates how easy it is to toggle fullscreen mode and reflect the current state using the useFullscreen
hook. The button text and styles change based on whether the component is in fullscreen mode or not.
Conclusion
Building a reusable useFullscreen
hook in React not only simplifies your codebase but also ensures you have a consistent way to manage fullscreen functionality across multiple components. By tracking fullscreen state, handling browser compatibility, and abstracting logic into a hook, you can create a more maintainable and robust application.
I hope this walkthrough has given you a clear understanding of how to build a fullscreen hook in React with TypeScript. This solution is scalable, reusable, and easy to integrate, making it a great addition to any project that requires fullscreen capabilities.