Hone logo
Hone
Problems

Implement useFullscreen Hook for Fullscreen API in React

In modern web applications, users often benefit from a fullscreen viewing experience, especially for media players, games, or detailed content. This challenge requires you to build a custom React hook, useFullscreen, that leverages the browser's Fullscreen API to enable and disable fullscreen mode for a specified DOM element.

Problem Description

Your task is to create a reusable React hook named useFullscreen written in TypeScript. This hook should manage the fullscreen state for a given DOM element. It should provide a boolean state indicating whether the element is currently in fullscreen mode and functions to request and exit fullscreen.

Key requirements:

  • The hook should accept a ref to the DOM element that will be toggled into fullscreen.
  • It should return an object containing:
    • isFullscreen: A boolean value representing the current fullscreen state.
    • requestFullscreen: A function to request fullscreen for the specified element.
    • exitFullscreen: A function to exit fullscreen mode.
  • The hook should handle the lifecycle of fullscreen events, updating its state accordingly.
  • It should gracefully handle cases where the Fullscreen API is not supported by the browser.
  • Ensure proper cleanup to remove event listeners when the component unmounts.

Expected behavior:

  • When requestFullscreen is called, the target element should enter fullscreen mode. isFullscreen should update to true.
  • When exitFullscreen is called, the target element should exit fullscreen mode. isFullscreen should update to false.
  • The hook should react to native browser fullscreen events (e.g., pressing the Escape key) and update isFullscreen accordingly.

Edge cases to consider:

  • Browser does not support the Fullscreen API.
  • The provided ref is null or undefined initially.
  • Fullscreen is requested for an element that is not currently mounted or visible.

Examples

Example 1:

import React, { useRef } from 'react';
import { useFullscreen } from './useFullscreen'; // Assuming hook is in './useFullscreen'

function MyComponent() {
  const videoRef = useRef<HTMLVideoElement>(null);
  const { isFullscreen, requestFullscreen, exitFullscreen } = useFullscreen(videoRef);

  return (
    <div>
      <video ref={videoRef} width="300" controls>
        <source src="your-video.mp4" type="video/mp4" />
      </video>
      <button onClick={() => requestFullscreen()}>
        {isFullscreen ? 'Exit Fullscreen' : 'Enter Fullscreen'}
      </button>
    </div>
  );
}

Output: When the "Enter Fullscreen" button is clicked, the video element enters fullscreen. The button text changes to "Exit Fullscreen". Pressing Escape or clicking the button again will exit fullscreen, and the button text reverts. isFullscreen will be true when in fullscreen, false otherwise.

Example 2:

import React, { useRef } from 'react';
import { useFullscreen } from './useFullscreen';

function DocumentViewer() {
  const documentDivRef = useRef<HTMLDivElement>(null);
  const { isFullscreen, requestFullscreen, exitFullscreen } = useFullscreen(documentDivRef);

  return (
    <div ref={documentDivRef} style={{ border: '1px solid black', padding: '20px', height: '300px' }}>
      <h1>Important Document</h1>
      <p>This is some content that might benefit from fullscreen viewing.</p>
      {!isFullscreen && (
        <button onClick={() => requestFullscreen()}>View in Fullscreen</button>
      )}
      {isFullscreen && (
        <button onClick={() => exitFullscreen()}>Exit Document View</button>
      )}
    </div>
  );
}

Output: Clicking "View in Fullscreen" makes the div element fullscreen. The "View in Fullscreen" button disappears, and the "Exit Document View" button appears. Clicking "Exit Document View" returns the div to its normal size. isFullscreen tracks this state.

Example 3: (API Not Supported)

// Assume browser does not support Fullscreen API
import React, { useRef } from 'react';
import { useFullscreen } from './useFullscreen';

function UnsupportedFeature() {
  const contentRef = useRef<HTMLDivElement>(null);
  const { isFullscreen, requestFullscreen, exitFullscreen } = useFullscreen(contentRef);

  return (
    <div ref={contentRef}>
      <p>This content could be viewed fullscreen.</p>
      <button onClick={() => requestFullscreen()} disabled={!document.fullscreenEnabled}>
        Enter Fullscreen (API Not Supported)
      </button>
      {isFullscreen && ( // This condition might never be met if API is not supported
        <button onClick={() => exitFullscreen()}>Exit Fullscreen</button>
      )}
    </div>
  );
}

Output: If the browser doesn't support the Fullscreen API, the requestFullscreen button will likely be disabled (or the API calls within it will be no-ops). isFullscreen will always remain false.

Constraints

  • The hook must be implemented using TypeScript.
  • The hook should only rely on standard browser APIs and React hooks. Do not use any external libraries for fullscreen management.
  • The ref passed to the hook will be of type React.RefObject<T extends HTMLElement>.
  • Performance should be reasonable; avoid unnecessary re-renders.

Notes

  • Familiarize yourself with the document.fullscreenEnabled, element.requestFullscreen(), and document.exitFullscreen() methods.
  • Pay attention to browser compatibility for the Fullscreen API. You might need to check vendor prefixes historically, though modern usage generally relies on standard properties.
  • Remember to handle potential errors that might occur during fullscreen requests.
  • Consider how the isFullscreen state should be updated when the user presses the Escape key or uses the browser's built-in fullscreen controls. Event listeners are crucial here.
  • Think about the cleanup process. Event listeners added should be removed to prevent memory leaks.
Loading editor...
typescript