Rooks

useScreenDetailsApi

About

Hook for multi-screen information and management using the Screen Details API. This hook provides access to information about all screens connected to the user's device and allows for reactive updates when screens are added, removed, or changed.

Note: This hook requires the Screen Details API which is experimental and only available in Chromium-based browsers with appropriate permissions.


Examples

Basic Usage

import React from "react";
import { useScreenDetailsApi } from "rooks";
 
export default function ScreenInfo() {
  const { 
    screens, 
    currentScreen, 
    isSupported, 
    hasPermission, 
    requestPermission, 
    error 
  } = useScreenDetailsApi();
 
  if (!isSupported) {
    return <div>Screen Details API is not supported in this browser</div>;
  }
 
  if (!hasPermission) {
    return (
      <div>
        <p>Permission required to access screen details</p>
        <button onClick={requestPermission}>Request Permission</button>
        {error && <p style={{ color: 'red' }}>Error: {error}</p>}
      </div>
    );
  }
 
  return (
    <div>
      <h2>Screen Information</h2>
      <p>Total screens: {screens.length}</p>
      
      <h3>Current Screen</h3>
      {currentScreen && (
        <div>
          <p>Label: {currentScreen.label}</p>
          <p>Resolution: {currentScreen.width}x{currentScreen.height}</p>
          <p>Available area: {currentScreen.availWidth}x{currentScreen.availHeight}</p>
          <p>Primary: {currentScreen.isPrimary ? 'Yes' : 'No'}</p>
          <p>Internal: {currentScreen.isInternal ? 'Yes' : 'No'}</p>
        </div>
      )}
      
      <h3>All Screens</h3>
      {screens.map((screen, index) => (
        <div key={index} style={{ border: '1px solid #ccc', padding: '10px', margin: '10px 0' }}>
          <h4>{screen.label}</h4>
          <p>Resolution: {screen.width}x{screen.height}</p>
          <p>Position: ({screen.left}, {screen.top})</p>
          <p>Available: {screen.availWidth}x{screen.availHeight}</p>
          <p>Primary: {screen.isPrimary ? 'Yes' : 'No'}</p>
          <p>Internal: {screen.isInternal ? 'Yes' : 'No'}</p>
        </div>
      ))}
    </div>
  );
}

Multi-Screen Window Management

import React, { useState } from "react";
import { useScreenDetailsApi } from "rooks";
 
export default function MultiScreenManager() {
  const { 
    screens, 
    primaryScreen, 
    externalScreens, 
    hasPermission, 
    requestPermission, 
    refresh 
  } = useScreenDetailsApi({ requestOnMount: true });
 
  const [openWindows, setOpenWindows] = useState([]);
 
  const openWindowOnScreen = (screen) => {
    const windowFeatures = `
      left=${screen.availLeft},
      top=${screen.availTop},
      width=${screen.availWidth},
      height=${screen.availHeight}
    `;
    
    const newWindow = window.open(
      '/demo-page',
      `_blank_${screen.label}`,
      windowFeatures
    );
    
    if (newWindow) {
      setOpenWindows(prev => [...prev, { window: newWindow, screen }]);
    }
  };
 
  const closeAllWindows = () => {
    openWindows.forEach(({ window }) => {
      if (!window.closed) {
        window.close();
      }
    });
    setOpenWindows([]);
  };
 
  if (!hasPermission) {
    return (
      <div>
        <h2>Multi-Screen Window Manager</h2>
        <button onClick={requestPermission}>Enable Multi-Screen Support</button>
      </div>
    );
  }
 
  return (
    <div>
      <h2>Multi-Screen Window Manager</h2>
      <div style={{ marginBottom: '20px' }}>
        <button onClick={refresh}>Refresh Screen Info</button>
        <button onClick={closeAllWindows}>Close All Windows</button>
      </div>
      
      <h3>Primary Screen</h3>
      {primaryScreen && (
        <div style={{ padding: '10px', backgroundColor: '#e8f5e8' }}>
          <p><strong>{primaryScreen.label}</strong></p>
          <p>Resolution: {primaryScreen.width}x{primaryScreen.height}</p>
          <button onClick={() => openWindowOnScreen(primaryScreen)}>
            Open Window on Primary Screen
          </button>
        </div>
      )}
      
      <h3>External Screens ({externalScreens.length})</h3>
      {externalScreens.map((screen, index) => (
        <div key={index} style={{ 
          padding: '10px', 
          backgroundColor: '#f0f0f0', 
          margin: '10px 0' 
        }}>
          <p><strong>{screen.label}</strong></p>
          <p>Resolution: {screen.width}x{screen.height}</p>
          <p>Position: ({screen.left}, {screen.top})</p>
          <button onClick={() => openWindowOnScreen(screen)}>
            Open Window on {screen.label}
          </button>
        </div>
      ))}
      
      <div style={{ marginTop: '20px' }}>
        <p>Open windows: {openWindows.length}</p>
      </div>
    </div>
  );
}

Screen Layout Visualization

import React from "react";
import { useScreenDetailsApi } from "rooks";
 
export default function ScreenLayout() {
  const { 
    screens, 
    currentScreen, 
    hasPermission, 
    requestPermission, 
    isLoading 
  } = useScreenDetailsApi();
 
  if (!hasPermission) {
    return (
      <div>
        <h2>Screen Layout Visualizer</h2>
        <button onClick={requestPermission}>
          {isLoading ? 'Loading...' : 'Request Permission'}
        </button>
      </div>
    );
  }
 
  // Calculate the bounding box of all screens
  const bounds = screens.reduce((acc, screen) => ({
    minX: Math.min(acc.minX, screen.left),
    minY: Math.min(acc.minY, screen.top),
    maxX: Math.max(acc.maxX, screen.left + screen.width),
    maxY: Math.max(acc.maxY, screen.top + screen.height),
  }), { minX: 0, minY: 0, maxX: 0, maxY: 0 });
 
  const totalWidth = bounds.maxX - bounds.minX;
  const totalHeight = bounds.maxY - bounds.minY;
  const scale = Math.min(800 / totalWidth, 600 / totalHeight, 1);
 
  return (
    <div>
      <h2>Screen Layout Visualizer</h2>
      <div style={{ 
        position: 'relative', 
        width: totalWidth * scale, 
        height: totalHeight * scale,
        border: '2px solid #333',
        margin: '20px 0'
      }}>
        {screens.map((screen, index) => (
          <div
            key={index}
            style={{
              position: 'absolute',
              left: (screen.left - bounds.minX) * scale,
              top: (screen.top - bounds.minY) * scale,
              width: screen.width * scale,
              height: screen.height * scale,
              border: screen.isPrimary ? '3px solid #007bff' : '2px solid #666',
              backgroundColor: screen === currentScreen ? '#e8f5e8' : '#f8f9fa',
              display: 'flex',
              flexDirection: 'column',
              justifyContent: 'center',
              alignItems: 'center',
              fontSize: '12px',
              overflow: 'hidden'
            }}
          >
            <div style={{ fontWeight: 'bold' }}>
              {screen.label}
            </div>
            <div>
              {screen.width}×{screen.height}
            </div>
            <div>
              {screen.isPrimary ? 'Primary' : 'Secondary'}
            </div>
            {screen === currentScreen && (
              <div style={{ color: '#007bff', fontWeight: 'bold' }}>
                Current
              </div>
            )}
          </div>
        ))}
      </div>
      
      <div style={{ marginTop: '20px' }}>
        <h3>Legend</h3>
        <div style={{ display: 'flex', gap: '20px' }}>
          <div style={{ display: 'flex', alignItems: 'center' }}>
            <div style={{ 
              width: '20px', 
              height: '20px', 
              border: '3px solid #007bff',
              backgroundColor: '#f8f9fa',
              marginRight: '8px'
            }}></div>
            Primary Screen
          </div>
          <div style={{ display: 'flex', alignItems: 'center' }}>
            <div style={{ 
              width: '20px', 
              height: '20px', 
              border: '2px solid #666',
              backgroundColor: '#f8f9fa',
              marginRight: '8px'
            }}></div>
            Secondary Screen
          </div>
          <div style={{ display: 'flex', alignItems: 'center' }}>
            <div style={{ 
              width: '20px', 
              height: '20px', 
              border: '2px solid #666',
              backgroundColor: '#e8f5e8',
              marginRight: '8px'
            }}></div>
            Current Screen
          </div>
        </div>
      </div>
    </div>
  );
}

Options

OptionTypeDefaultDescription
requestOnMountbooleanfalseWhether to automatically request permission on mount
autoRefreshbooleantrueWhether to automatically refresh screen details on events

Return Value

PropertyTypeDescription
screensScreenDetailed[]Array of all available screens
currentScreenScreenDetailed|nullCurrent screen where the browser window is displayed
primaryScreenScreenDetailed|nullPrimary screen (the main display)
externalScreensScreenDetailed[]External screens (non-primary screens)
isSupportedbooleanWhether the Screen Details API is supported
isLoadingbooleanWhether the hook is currently loading screen details
hasPermissionbooleanWhether permission has been granted
errorstring|nullError message if any operation failed
requestPermission() => Promise<void>Request permission to access screen details
refresh() => Promise<void>Manually refresh screen details

ScreenDetailed Object

PropertyTypeDescription
availLeftnumberX-coordinate of available screen area
availTopnumberY-coordinate of available screen area
availWidthnumberWidth of available screen area
availHeightnumberHeight of available screen area
leftnumberX-coordinate of total screen area
topnumberY-coordinate of total screen area
widthnumberWidth of total screen area
heightnumberHeight of total screen area
colorDepthnumberColor depth of the screen
pixelDepthnumberPixel depth of the screen
devicePixelRationumberDevice pixel ratio
isPrimarybooleanWhether this is the primary screen
isInternalbooleanWhether this is an internal screen
labelstringHuman-readable label for the screen

Browser Support

The Screen Details API is experimental and currently only supported in:

  • Chrome/Chromium-based browsers (version 100+)
  • Requires HTTPS context
  • Requires user permission (window-management permission)

Notes

  • The hook will automatically detect if the API is supported and provide appropriate fallbacks
  • Permission must be requested and granted before accessing screen details
  • The hook automatically sets up event listeners for screen changes when permission is granted
  • Screen details are automatically refreshed when screens are added, removed, or changed (unless autoRefresh is disabled)
  • All screen coordinates are in CSS pixels relative to the multi-screen coordinate system

On this page