Hooks
No hooks found in any category.
useFullscreen
domInstallation
npx usehooks-cli@latest add use-fullscreen
Description
A hook for managing fullscreen mode using the Fullscreen API. Provides cross-browser support for entering and exiting fullscreen mode with callback options.
Parameters
Name | Type | Default | Description |
---|---|---|---|
targetRef? | React.RefObject<Element> | - | Reference to the element to make fullscreen (defaults to document.documentElement) |
options? | UseFullscreenOptions | - | Configuration options for fullscreen behavior |
Parameter Properties
options properties:
Name | Type | Description |
---|---|---|
onEnter? | () => void | Callback fired when entering fullscreen mode |
onExit? | () => void | Callback fired when exiting fullscreen mode |
onError? | (error: Error) => void | Callback fired when fullscreen operation fails |
Return Type
UseFullscreenReturn
Property | Type | Description |
---|---|---|
isFullscreen | boolean | Whether currently in fullscreen mode |
isSupported | boolean | Whether the Fullscreen API is supported |
enter | (element?: Element) => Promise<void> | Enter fullscreen mode for the specified element |
exit | () => Promise<void> | Exit fullscreen mode |
toggle | (element?: Element) => Promise<void> | Toggle fullscreen mode |
element | Element | null | The current fullscreen element |
Examples
Basic Fullscreen Toggle
Simple fullscreen toggle for the entire page
1import { useFullscreen } from '@usehooks/use-fullscreen';
2
3function FullscreenDemo() {
4 const {
5 isFullscreen,
6 isSupported,
7 enter,
8 exit,
9 toggle
10 } = useFullscreen();
11
12 if (!isSupported) {
13 return <div>Fullscreen not supported</div>;
14 }
15
16 return (
17 <div style={{ padding: '20px' }}>
18 <h2>Fullscreen Demo</h2>
19 <p>Status: {isFullscreen ? 'Fullscreen' : 'Normal'}</p>
20
21 <div>
22 <button onClick={() => enter()}>Enter Fullscreen</button>
23 <button onClick={() => exit()}>Exit Fullscreen</button>
24 <button onClick={() => toggle()}>Toggle Fullscreen</button>
25 </div>
26
27 {isFullscreen && (
28 <div style={{
29 position: 'fixed',
30 top: 0,
31 left: 0,
32 right: 0,
33 bottom: 0,
34 backgroundColor: 'black',
35 color: 'white',
36 display: 'flex',
37 alignItems: 'center',
38 justifyContent: 'center',
39 flexDirection: 'column'
40 }}>
41 <h1>Fullscreen Mode</h1>
42 <button onClick={() => exit()}>Exit Fullscreen</button>
43 </div>
44 )}
45 </div>
46 );
47}
Element-specific Fullscreen
Make a specific element fullscreen with ref
1import { useFullscreen } from '@usehooks/use-fullscreen';
2import { useRef } from 'react';
3
4function VideoPlayer() {
5 const videoRef = useRef<HTMLVideoElement>(null);
6 const {
7 isFullscreen,
8 enter,
9 exit,
10 toggle
11 } = useFullscreen(videoRef, {
12 onEnter: () => console.log('Video entered fullscreen'),
13 onExit: () => console.log('Video exited fullscreen'),
14 onError: (error) => console.error('Fullscreen error:', error)
15 });
16
17 return (
18 <div>
19 <video
20 ref={videoRef}
21 width="400"
22 height="300"
23 controls
24 style={{
25 border: isFullscreen ? 'none' : '2px solid #ccc',
26 backgroundColor: 'black'
27 }}
28 >
29 <source src="/sample-video.mp4" type="video/mp4" />
30 Your browser does not support the video tag.
31 </video>
32
33 <div style={{ marginTop: '10px' }}>
34 <button onClick={() => toggle()}>
35 {isFullscreen ? 'Exit' : 'Enter'} Fullscreen
36 </button>
37 <p>Video is {isFullscreen ? 'fullscreen' : 'normal'}</p>
38 </div>
39 </div>
40 );
41}
Image Gallery Fullscreen
Fullscreen image viewer with navigation
1import { useFullscreen } from '@usehooks/use-fullscreen';
2import { useRef, useState } from 'react';
3
4function ImageGallery() {
5 const imageRef = useRef<HTMLDivElement>(null);
6 const [currentImage, setCurrentImage] = useState(0);
7 const {
8 isFullscreen,
9 enter,
10 exit
11 } = useFullscreen(imageRef);
12
13 const images = [
14 '/image1.jpg',
15 '/image2.jpg',
16 '/image3.jpg'
17 ];
18
19 const nextImage = () => {
20 setCurrentImage((prev) => (prev + 1) % images.length);
21 };
22
23 const prevImage = () => {
24 setCurrentImage((prev) => (prev - 1 + images.length) % images.length);
25 };
26
27 const handleImageClick = () => {
28 if (!isFullscreen) {
29 enter();
30 }
31 };
32
33 return (
34 <div>
35 <div
36 ref={imageRef}
37 style={{
38 position: 'relative',
39 width: isFullscreen ? '100vw' : '400px',
40 height: isFullscreen ? '100vh' : '300px',
41 backgroundColor: 'black',
42 display: 'flex',
43 alignItems: 'center',
44 justifyContent: 'center',
45 cursor: isFullscreen ? 'default' : 'pointer'
46 }}
47 onClick={handleImageClick}
48 >
49 <img
50 src={images[currentImage]}
51 alt={`Image ${currentImage + 1}`}
52 style={{
53 maxWidth: '100%',
54 maxHeight: '100%',
55 objectFit: 'contain'
56 }}
57 />
58
59 {isFullscreen && (
60 <>
61 <button
62 onClick={(e) => {
63 e.stopPropagation();
64 prevImage();
65 }}
66 style={{
67 position: 'absolute',
68 left: '20px',
69 top: '50%',
70 transform: 'translateY(-50%)',
71 fontSize: '24px',
72 padding: '10px'
73 }}
74 >
75 ←
76 </button>
77
78 <button
79 onClick={(e) => {
80 e.stopPropagation();
81 nextImage();
82 }}
83 style={{
84 position: 'absolute',
85 right: '20px',
86 top: '50%',
87 transform: 'translateY(-50%)',
88 fontSize: '24px',
89 padding: '10px'
90 }}
91 >
92 →
93 </button>
94
95 <button
96 onClick={(e) => {
97 e.stopPropagation();
98 exit();
99 }}
100 style={{
101 position: 'absolute',
102 top: '20px',
103 right: '20px',
104 fontSize: '18px',
105 padding: '10px'
106 }}
107 >
108 ✕
109 </button>
110 </>
111 )}
112 </div>
113
114 {!isFullscreen && (
115 <div style={{ marginTop: '10px' }}>
116 <button onClick={prevImage}>Previous</button>
117 <span style={{ margin: '0 10px' }}>
118 {currentImage + 1} of {images.length}
119 </span>
120 <button onClick={nextImage}>Next</button>
121 <p>Click image to view fullscreen</p>
122 </div>
123 )}
124 </div>
125 );
126}
Dependencies
react
Notes
- •Requires user gesture to enter fullscreen mode
- •Cross-browser support for webkit, moz, and ms prefixes
- •Automatically handles fullscreen change events
- •Cleans up event listeners on component unmount
- •Some browsers may have restrictions on which elements can be fullscreen
- •Fullscreen mode may be blocked by browser settings or extensions
Implementation
1'use client';
2
3import { useState, useEffect, useCallback, useRef } from "react";
4
5export interface UseFullscreenOptions {
6 onEnter?: () => void;
7 onExit?: () => void;
8 onError?: (error: Error) => void;
9}
10
11export interface UseFullscreenReturn {
12 isFullscreen: boolean;
13 isSupported: boolean;
14 enter: (element?: Element) => Promise<void>;
15 exit: () => Promise<void>;
16 toggle: (element?: Element) => Promise<void>;
17 element: Element | null;
18}
19
20export function useFullscreen(
21 targetRef?: React.RefObject<Element>,
22 options: UseFullscreenOptions = {}
23): UseFullscreenReturn {
24 const [isFullscreen, setIsFullscreen] = useState(false);
25 const [element, setElement] = useState<Element | null>(null);
26 const optionsRef = useRef(options);
27
28 // Update options ref when options change
29 useEffect(() => {
30 optionsRef.current = options;
31 }, [options]);
32
33 // Check if fullscreen is supported
34 const isSupported = Boolean(
35 document.fullscreenEnabled ||
36 (document as any).webkitFullscreenEnabled ||
37 (document as any).mozFullScreenEnabled ||
38 (document as any).msFullscreenEnabled
39 );
40
41 // Handle fullscreen change events
42 useEffect(() => {
43 const handleFullscreenChange = () => {
44 const fullscreenElement =
45 document.fullscreenElement ||
46 (document as any).webkitFullscreenElement ||
47 (document as any).mozFullScreenElement ||
48 (document as any).msFullscreenElement;
49
50 const isCurrentlyFullscreen = Boolean(fullscreenElement);
51 setIsFullscreen(isCurrentlyFullscreen);
52 setElement(fullscreenElement);
53
54 if (isCurrentlyFullscreen) {
55 optionsRef.current.onEnter?.();
56 } else {
57 optionsRef.current.onExit?.();
58 }
59 };
60
61 const handleFullscreenError = () => {
62 optionsRef.current.onError?.(
63 new Error("Failed to enter fullscreen mode")
64 );
65 };
66
67 // Add event listeners for different browsers
68 document.addEventListener("fullscreenchange", handleFullscreenChange);
69 document.addEventListener("webkitfullscreenchange", handleFullscreenChange);
70 document.addEventListener("mozfullscreenchange", handleFullscreenChange);
71 document.addEventListener("MSFullscreenChange", handleFullscreenChange);
72
73 document.addEventListener("fullscreenerror", handleFullscreenError);
74 document.addEventListener("webkitfullscreenerror", handleFullscreenError);
75 document.addEventListener("mozfullscreenerror", handleFullscreenError);
76 document.addEventListener("MSFullscreenError", handleFullscreenError);
77
78 // Set initial state
79 handleFullscreenChange();
80
81 return () => {
82 document.removeEventListener("fullscreenchange", handleFullscreenChange);
83 document.removeEventListener(
84 "webkitfullscreenchange",
85 handleFullscreenChange
86 );
87 document.removeEventListener(
88 "mozfullscreenchange",
89 handleFullscreenChange
90 );
91 document.removeEventListener(
92 "MSFullscreenChange",
93 handleFullscreenChange
94 );
95
96 document.removeEventListener("fullscreenerror", handleFullscreenError);
97 document.removeEventListener(
98 "webkitfullscreenerror",
99 handleFullscreenError
100 );
101 document.removeEventListener("mozfullscreenerror", handleFullscreenError);
102 document.removeEventListener("MSFullscreenError", handleFullscreenError);
103 };
104 }, []);
105
106 const enter = useCallback(
107 async (elementToFullscreen?: Element) => {
108 if (!isSupported) {
109 throw new Error("Fullscreen API is not supported");
110 }
111
112 const target =
113 elementToFullscreen || targetRef?.current || document.documentElement;
114
115 if (!target) {
116 throw new Error("No element provided for fullscreen");
117 }
118
119 try {
120 if (target.requestFullscreen) {
121 await target.requestFullscreen();
122 } else if ((target as any).webkitRequestFullscreen) {
123 await (target as any).webkitRequestFullscreen();
124 } else if ((target as any).mozRequestFullScreen) {
125 await (target as any).mozRequestFullScreen();
126 } else if ((target as any).msRequestFullscreen) {
127 await (target as any).msRequestFullscreen();
128 } else {
129 throw new Error("Fullscreen API is not supported");
130 }
131 } catch (error) {
132 optionsRef.current.onError?.(error as Error);
133 throw error;
134 }
135 },
136 [isSupported, targetRef]
137 );
138
139 const exit = useCallback(async () => {
140 if (!isSupported) {
141 throw new Error("Fullscreen API is not supported");
142 }
143
144 try {
145 if (document.exitFullscreen) {
146 await document.exitFullscreen();
147 } else if ((document as any).webkitExitFullscreen) {
148 await (document as any).webkitExitFullscreen();
149 } else if ((document as any).mozCancelFullScreen) {
150 await (document as any).mozCancelFullScreen();
151 } else if ((document as any).msExitFullscreen) {
152 await (document as any).msExitFullscreen();
153 } else {
154 throw new Error("Fullscreen API is not supported");
155 }
156 } catch (error) {
157 optionsRef.current.onError?.(error as Error);
158 throw error;
159 }
160 }, [isSupported]);
161
162 const toggle = useCallback(
163 async (elementToFullscreen?: Element) => {
164 if (isFullscreen) {
165 await exit();
166 } else {
167 await enter(elementToFullscreen);
168 }
169 },
170 [isFullscreen, enter, exit]
171 );
172
173 return {
174 isFullscreen,
175 isSupported,
176 enter,
177 exit,
178 toggle,
179 element,
180 };
181}
182