← Back to Tutorials Chapter 18

Window Management

Display Modes

Use CSS media queries to detect and adapt to different display modes:

/* CSS display mode detection */
@media (display-mode: browser) {
  /* Regular browser tab */
  body::before { content: "Browser mode"; }
}

@media (display-mode: standalone) {
  /* Installed PWA */
  body { background: var(--app-bg); }
  .browser-chrome { display: none; }
}

@media (display-mode: minimal-ui) {
  /* Minimal browser UI */
  .minimal-ui-hint { display: block; }
}

@media (display-mode: fullscreen) {
  /* Full screen */
  body { cursor: none; }
}

/* JavaScript display mode detection */
const displayMode = window.matchMedia('(display-mode: standalone)').matches
  ? 'standalone'
  : window.matchMedia('(display-mode: minimal-ui)').matches
    ? 'minimal-ui'
    : window.matchMedia('(display-mode: fullscreen)').matches
      ? 'fullscreen'
      : 'browser';

console.log('Current display mode:', displayMode);

Window Controls Overlay

The Window Controls Overlay API lets you customize the title bar area of installed desktop PWAs.

// manifest.json - Enable overlay
{
  "display_override": ["window-controls-overlay"],
  "display": "standalone"
}

// CSS for the title bar area
#title-bar {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: 40px;
  display: flex;
  align-items: center;
  padding-left: env(titlebar-area-x, 0);
  padding-top: env(titlebar-area-y, 0);
  width: env(titlebar-area-width, 100%);
  height: env(titlebar-area-height, 40px);
  -webkit-app-region: drag;
  background: var(--theme-color);
}

#title-bar button {
  -webkit-app-region: no-drag;
}

// JavaScript API
if ('windowControlsOverlay' in navigator) {
  const overlay = navigator.windowControlsOverlay;

  // Check if overlay is visible
  console.log('Overlay visible:', overlay.visible);

  // Listen for geometry changes
  overlay.addEventListener('geometrychange', (event) => {
    const { x, y, width, height } = event.titlebarAreaRect;
    console.log('Title bar area:', { x, y, width, height });
  });
}

Multi-window Management

Open and manage multiple windows from your PWA:

// Open a new window
async function openDocumentWindow(docId) {
  const windowRef = window.open(
    `/document?id=${docId}`,
    'doc-window',
    'width=800,height=600'
  );

  // Communicate between windows
  windowRef.addEventListener('message', (event) => {
    if (event.data.type === 'DOCUMENT_SAVED') {
      refreshDocumentList();
    }
  });
}

// Post message to opener window
window.opener.postMessage({
  type: 'DOCUMENT_SAVED',
  docId: 123
}, '*');

// Get all windows (from Service Worker)
self.addEventListener('message', (event) => {
  self.clients.matchAll({ type: 'window' }).then(clients => {
    clients.forEach(client => {
      client.postMessage({ type: 'UPDATE_AVAILABLE' });
    });
  });
});

Screen API

// Keep screen on (Wake Lock)
async function keepScreenOn() {
  if ('wakeLock' in navigator) {
    try {
      const wakeLock = await navigator.wakeLock.request('screen');
      console.log('Wake lock acquired');

      wakeLock.addEventListener('release', () => {
        console.log('Wake lock released');
      });
    } catch (err) {
      console.error('Wake lock failed:', err);
    }
  }
}

// Detect screen orientation
screen.orientation.addEventListener('change', () => {
  console.log('Orientation:', screen.orientation.type);
});
Exercise: Create a PWA that uses the Window Controls Overlay for a custom title bar with the app name and a "minimize to tray" action. Also implement a multi-window note editor where each note opens in a separate window that can post messages back to the main window.