Managing native browser APIs in React is always a bit of a tightrope walk. But few APIs are as notoriously frustrating as the Fullscreen API. Between varying implementations for Safari (webkit), Firefox (moz), and Edge/IE (ms), building a custom fullscreen button can quickly devolve into a spaghetti-mess of compatibility checks.
In the latest release of react-hook-lab, we are addressing this head-on with the introduction of a robust, production-ready hook: useFullscreen.
Alongside this, we have systematically optimized the library's compilation profile using TypeScript type-only imports to keep your production bundles as lean as possible.
The Problem with Native Fullscreen
To make an element fullscreen natively, you have to write checks like this:
if (elem.requestFullscreen) {
elem.requestFullscreen();
} else if (elem.webkitRequestFullscreen) {
elem.webkitRequestFullscreen();
} else if (elem.msRequestFullscreen) {
elem.msRequestFullscreen();
}
This degrades code readability, ignores reactive state synchronization, and introduces potential runtime errors if handled incorrectly.
Enter useFullscreen
The new useFullscreen hook abstracts away all prefix quirks, tracks the active fullscreen state across document-level events, and provides safe, promise-based controllers.
Here are two practical examples of how to drop it into your React projects today.
Example 1: Building a Custom Video Player Control
When creating video elements, you often want a custom UI button to trigger fullscreen mode for the video element itself.
import React from "react";
import { useFullscreen } from "react-hook-lab";
export function VideoPlayer() {
const { ref, isFullscreen, toggle, error } = useFullscreen<HTMLVideoElement>();
return (
<div style={{ maxWidth: "600px", margin: "20px auto", textAlign: "center" }}>
<h3>Custom React Video Player</h3>
{error && <p style={{ color: "red" }}>Error: {error.message}</p>}
<video
ref={ref}
src="https://www.w3schools.com/html/mov_bbb.mp4"
controls
style={{ width: "100%", borderRadius: "8px" }}
/>
<button
onClick={toggle}
style={{ marginTop: "10px", padding: "8px 16px", cursor: "pointer" }}
>
{isFullscreen ? "Exit Fullscreen" : "Go Fullscreen"}
</button>
</div>
);
}
Example 2: Interactive Dashboard Widget Focus
You might want to allow users to zoom in and focus on a specific dashboard widget or presentation slide, blocking out other distractions.
import React from "react";
import { useFullscreen } from "react-hook-lab";
export function DashboardWidget() {
const { ref, enter, exit, isFullscreen } = useFullscreen<HTMLDivElement>();
return (
<div
ref={ref}
style={{
background: isFullscreen ? "#1e1e1e" : "#f5f5f5",
color: isFullscreen ? "#ffffff" : "#000000",
padding: "40px",
borderRadius: "12px",
textAlign: "center",
border: "1px solid #ddd"
}}
>
<h2>Interactive Sales Data</h2>
<p>Analyze key performance indicators in detailed fullscreen view.</p>
<div style={{ margin: "40px 0" }}>
{/* Imagine a complex chart here */}
<span style={{ fontSize: "48px" }}>📊 +148%</span>
</div>
{isFullscreen ? (
<button onClick={exit} style={{ padding: "10px 20px" }}>
Exit Focus Mode
</button>
) : (
<button onClick={enter} style={{ padding: "10px 20px" }}>
Maximize Chart
</button>
)}
</div>
);
}
Behind the Scenes: Library-Wide Performance Tweaks
We didn't just add new functionality; we also improved our existing hooks. We systematically refactored internal declarations to use TypeScript import type across the entire package, including popular hooks like useAsync, useCamera, useClickOutside, useToggle, and useDeepMemo.
By ensuring that types are explicitly declared, modern bundlers (like Vite, Webpack, and Rollup) can safely strip typescript definitions during the build process. This leads to superior tree-shaking and minimizes bundle sizes for the end user.
We also patched a potential runtime warning in our debug helper useRenderReason to prevent unexpected Node-type environment errors during server-side rendering.
Resources & Links
- GitHub Repository: Saurav-TB-Pandey/react-hook-lab
- NPM Package: react-hook-lab on NPM
- Author LinkedIn: Saurav Pandey
Originally published on my blog. You can read the alternative breakdown here.
Top comments (0)