Window Management
PWAs get their own window -- and with it, the old 90s window APIs that tabbed browsers killed. The Multi-Screen Window Placement API and Windows Controls Overlay go further, letting PWAs span displays and render HTML in the title bar.
window.moveTo() and window.resizeTo() shipped in Netscape 2.0 in 1996. They let JavaScript reposition and resize the browser window.
They have been effectively dead for 25 years.
Once tabbed browsing arrived, a JavaScript call that tried to move "the window" became ambiguous -- there were other tabs in that window, and other apps using it. Browsers silently ignored the calls. The APIs stayed in the spec but did nothing.
Install your app as a PWA and you get your own window. A window no other tab shares. And suddenly the APIs from 1996 work again.
Your Own Window
An installed PWA runs in a standalone window. That window belongs to the app. No other tabs, no other origins. When you call window.moveTo(100, 200), the browser moves that window.
You can also open additional windows of the same app:
const newWindow = window.open('/dashboard', '_blank', 'width=800,height=600')Each opened window is a new instance of your PWA, at the specified dimensions, positioned wherever you like. All windows share the same origin and can communicate via BroadcastChannel or postMessage.
This is what made multi-window creative tools possible on the web -- a canvas editor where the tool palette is a separate window, positioned where the user last left it.
Multi-Screen Window Placement
Single-screen positioning is useful. Multi-screen positioning is the real unlock. Professionals commonly have two, three, or more monitors -- a presentation app that can move its slide view to the external projector is solving a real problem.
// Request permission and get screen details
const screens = await window.getScreenDetails()
// All connected screens
screens.screens.forEach(screen => {
console.log(screen.label) // "Built-in Retina Display", "DELL U2722D", etc.
console.log(screen.availLeft) // x-coordinate of the screen
console.log(screen.availTop) // y-coordinate of the screen
console.log(screen.availWidth) // usable width (excludes OS taskbar)
console.log(screen.availHeight) // usable height
console.log(screen.isPrimary) // true for the main display
console.log(screen.isExtended) // true for any secondary display
})
// The screen the current window is on
console.log(screens.currentScreen)window.getScreenDetails() requires a user permission grant the first time it is called. After permission is granted, screenschange fires whenever the connected display configuration changes.
To move the current window to a specific screen:
const [primaryScreen, secondaryScreen] = screens.screens.sort(
(a, b) => a.isPrimary ? -1 : 1
)
// Move to secondary screen, fill it
window.moveTo(secondaryScreen.availLeft, secondaryScreen.availTop)
window.resizeTo(secondaryScreen.availWidth, secondaryScreen.availHeight)This API is not limited to installed PWAs -- it works on websites running in a browser tab too. The permission dialog is the same.
ExpandWindow Management APIs: legacy moveTo/resizeTo, multi-screen placement, and Windows Controls Overlay
Windows Controls Overlay
The title bar is wasted space by default. A thin strip showing the app name and three window control buttons. Nothing else.
Windows Controls Overlay changes that. When you opt in via the manifest, the browser lets your HTML and CSS render all the way into the title bar region -- behind the traffic-light buttons on macOS, and to the left of the close/minimize/maximize buttons on Windows.
{
"display_override": ["window-controls-overlay"],
"display": "standalone"
}With that in the manifest, the PWA gains CSS environment variables that tell you the exact geometry of the non-draggable region:
.title-bar-content {
position: fixed;
left: env(titlebar-area-x);
top: env(titlebar-area-y);
width: env(titlebar-area-width);
height: env(titlebar-area-height);
/* -webkit-app-region: drag; makes this area draggable */
}A search bar in the title bar. A tab strip. The current document name. These are all possible with CSS and env() variables.
The classic example is Wikipedia as a PWA: a search field sits directly in the title bar. The user can type a search without the app viewport scrolling at all.
Current support: Chrome and Edge on desktop. Not Safari, not mobile.
Support
window.getScreenDetails() and Windows Controls Overlay both require Chromium on desktop. window.moveTo() and window.resizeTo() work in any browser when the app is running in a standalone window.
if ('getScreenDetails' in window) {
// Multi-Screen Window Placement API is available
}The next OS integration API makes your PWA act like a default file opener. File Handling and Protocol Handlers let a double-click on a .recipe file in the OS file manager launch your PWA with that file ready to read.
The Essentials
- An installed PWA runs in its own window --
moveTo,resizeTo, andopen()work again because no other tabs share the window. window.getScreenDetails()returns all connected screens with coordinates, sizes, and labels. Works in browser tabs too (not PWA-only).screenschangefires when the display configuration changes -- screens added, removed, or repositioned.- Windows Controls Overlay (
"display_override": ["window-controls-overlay"]) lets you render HTML/CSS in the title bar. Useenv(titlebar-area-x/y/width/height)for geometry. Chrome/Edge desktop only. - All window control APIs require Chromium. The multi-screen API also works in regular browser tabs.
Further Reading and Watching
- Manage several displays with the Window Management API -- Chrome for Developers -- official guide with screen enumeration, event handling, the coordinate system, and permission model
- Window Management API -- MDN -- full API reference for
getScreenDetails(),ScreenDetails,Screenproperties, andscreenschange
Keep reading