Managing several displays with the Window Management API Stay organized with collections Save and categorize content based on your preferences.
Get information about connected displays and position windows relative to those displays.
Success: The Window Management API was part of thecapabilities project and is now available from Chrome 100.Window Management API
The Window Management API allows you to enumerate the displays connected to your machineand to place windows on specific screens.
Note: The Window Management API is distinct from the proposedViewport Segments Property,which is concerned with the representation of the regions of the window that reside on separate(adjacent) displays, for example, on foldable devices.Note: The Window Management API was formerly known as the Multi-Screen Window Placement API.Suggested use cases
Examples of sites that may use this API include:
- Multi-window graphics editors à laGimp can place variousediting tools in accurately positioned windows.
- Virtual trading desks can show market trends in multiple windows any of which can be viewed infullscreen mode.
- Slideshow apps can show speaker notes on the internal primary screen and the presentation on anexternal projector.
How to use the Window Management API
The problem
The time-tested approach to controlling windows,Window.open()
, is unfortunatelyunaware of additional screens. While some aspects of this API seem a little archaic, such as itswindowFeatures
DOMString
parameter, it has nevertheless served us well over the years. To specify a window'sposition, you can pass thecoordinates asleft
andtop
(orscreenX
andscreenY
respectively) and pass the desiredsize aswidth
andheight
(orinnerWidth
andinnerHeight
respectively). For example, to open a400×300 window at 50 pixels from the left and 50 pixels from the top, this is the code that youcould use:
constpopup=window.open('https://example.com/','My Popup','left=50,top=50,width=400,height=300',);
You can get information about the current screen by looking at thewindow.screen
property, whichreturns aScreen
object. This is theoutput on my MacBook Pro 13″:
window.screen;/* Output from my MacBook Pro 13″: availHeight: 969 availLeft: 0 availTop: 25 availWidth: 1680 colorDepth: 30 height: 1050 isExtended: true onchange: null orientation: ScreenOrientation {angle: 0, type: "landscape-primary", onchange: null} pixelDepth: 30 width: 1680*/
Like most people working in tech, I have had to adapt myself to the new work reality and set up mypersonal home office. Mine looks like on the photo below (if you are interested, you can read thefull details about my setup).The iPad next to my MacBook is connected to the laptop viaSidecar, so whenever I need to, I can quickly turn theiPad into a second screen.

If I want to take advantage of the bigger screen, I can put the popup from thecode sample above on to the second screen. I do itlike this:
popup.moveTo(2500,50);
This is a rough guess, since there is no way to know the dimensions of the second screen. The infofromwindow.screen
only covers the built-in screen, but not the iPad screen. The reportedwidth
of the built-in screen was1680
pixels, so moving to2500
pixelsmight work to shift thewindow over to the iPad, sinceI happen to know that it is located on the right of my MacBook. Howcan I do this in the general case? Turns out, there is a better way than guessing. That way is theWindow Management API.
Feature detection
To check if the Window Management API is supported, use:
if('getScreenDetails'inwindow){// The Window Management API is supported.}
Thewindow-management
permission
Note: The oldwindow-placement
permission name isno longer supported.Before I can use the Window Management API, I must ask the user for permission to do so.Thewindow-management
permission can be queried with thePermissions API like so:
letgranted=false;try{const{state}=awaitnavigator.permissions.query({name:'window-management'});granted=state==='granted';}catch{// Nothing.}
While browsers with the old and the new permission name are in use, be sure to use defensive code when requesting permission, as in the example below.
asyncfunctiongetWindowManagementPermissionState(){letstate;// The new permission name.try{({state}=awaitnavigator.permissions.query({name:"window-management",}));}catch(err){return`${err.name}:${err.message}`;}returnstate;}document.querySelector("button").addEventListener("click",async()=>{conststate=awaitgetWindowManagementPermissionState();document.querySelector("pre").textContent=state;});
The browsercanchoose to show the permission prompt dynamically on the first attempt to use any of the methods ofthe new API. Read on to learn more.
Thewindow.screen.isExtended
property
To find out if more than one screen is connected to my device, I access thewindow.screen.isExtended
property. It returnstrue
orfalse
. For my setup, it returnstrue
.
window.screen.isExtended;// Returns `true` or `false`.
ThegetScreenDetails()
method
Now that I know that the current setup is multi-screen, I can obtain more information about thesecond screen usingWindow.getScreenDetails()
. Calling this function will show a permission prompt thatasks me whether the site may open and place windows on my screen. The function returns a promisethat resolves with aScreenDetailed
object. On my MacBook Pro 13 with a connected iPad,this includes ascreens
field with twoScreenDetailed
objects:
awaitwindow.getScreenDetails();/* Output from my MacBook Pro 13″ with the iPad attached:{ currentScreen: ScreenDetailed {left: 0, top: 0, isPrimary: true, isInternal: true, devicePixelRatio: 2, …} oncurrentscreenchange: null onscreenschange: null screens: [{ // The MacBook Pro availHeight: 969 availLeft: 0 availTop: 25 availWidth: 1680 colorDepth: 30 devicePixelRatio: 2 height: 1050 isExtended: true isInternal: true isPrimary: true label: "Built-in Retina Display" left: 0 onchange: null orientation: ScreenOrientation {angle: 0, type: "landscape-primary", onchange: null} pixelDepth: 30 top: 0 width: 1680 }, { // The iPad availHeight: 999 availLeft: 1680 availTop: 25 availWidth: 1366 colorDepth: 24 devicePixelRatio: 2 height: 1024 isExtended: true isInternal: false isPrimary: false label: "Sidecar Display (AirPlay)" left: 1680 onchange: null orientation: ScreenOrientation {angle: 0, type: "landscape-primary", onchange: null} pixelDepth: 24 top: 0 width: 1366 }]}*/
Information about the connected screens is available in thescreens
array. Note how the value ofleft
for the iPad starts at1680
, which is exactly thewidth
of the built-in display. Thisallows me to determine exactly how the screens are arranged logically (next to each other, on top ofeach other, etc.). There is also data now for each screen to show whether it is anisInternal
oneand whether it is anisPrimary
one. Note that the built-in screenis not necessarily the primary screen.
ThecurrentScreen
field is a live object corresponding to the currentwindow.screen
. The objectis updated on cross-screen window placements or device changes.
"Built-in Retina Display"
, instead of less descriptive placeholders, like"Internal Display 1"
.Thescreenschange
event
The only thing missing now is a way to detect when my screen setup changes. A new event,screenschange
, does exactly that: it fires whenever the screen constellation is modified. (Noticethat "screens" is plural in the event name.) This means the event fires whenever a new screen or anexisting screen is (physically or virtually in the case of Sidecar) plugged in or unplugged.
Note that you need to look up the new screen details asynchronously, thescreenschange
eventitself does not provide this data. To look up the screen details, use the live object from a cachedScreens
interface.
constscreenDetails=awaitwindow.getScreenDetails();letcachedScreensLength=screenDetails.screens.length;screenDetails.addEventListener('screenschange',(event)=>{if(screenDetails.screens.length!==cachedScreensLength){console.log(`The screen count changed from${cachedScreensLength} to${screenDetails.screens.length}`,);cachedScreensLength=screenDetails.screens.length;}});
Thecurrentscreenchange
event
If I am only interested in changes to the current screen (that is, the value of the live objectcurrentScreen
), I can listen for thecurrentscreenchange
event.
constscreenDetails=awaitwindow.getScreenDetails();screenDetails.addEventListener('currentscreenchange',async(event)=>{constdetails=screenDetails.currentScreen;console.log('The current screen has changed.',event,details);});
Thechange
event
Finally, if I am only interested in changes to a concrete screen, I can listen to that screen'schange
event.
constfirstScreen=(awaitwindow.getScreenDetails())[0];firstScreen.addEventListener('change',async(event)=>{console.log('The first screen has changed.',event,firstScreen);});
New fullscreen options
Until now, you could request that elements be displayed in fullscreen mode via the aptly namedrequestFullScreen()
method. The method takes anoptions
parameter where you can passFullscreenOptions
. So far,its only property has beennavigationUI
.The Window Management API adds a newscreen
property that allows you to determinewhich screen to start the fullscreen view on. For example, if you want to make the primary screenfullscreen:
try{constprimaryScreen=(awaitgetScreenDetails()).screens.filter((screen)=>screen.isPrimary)[0];awaitdocument.body.requestFullscreen({screen:primaryScreen});}catch(err){console.error(err.name,err.message);}
Polyfill
It is not possible to polyfill the Window Management API, but you can shim its shape soyou can code exclusively against the new API:
if(!('getScreenDetails'inwindow)){// Returning a one-element array with the current screen,// noting that there might be more.window.getScreenDetails=async()=>[window.screen];// Set to `false`, noting that this might be a lie.window.screen.isExtended=false;}
The other aspects of the API, that is, the various screen change events and thescreen
property oftheFullscreenOptions
, would simply never fire or silently be ignored respectively bynon-supporting browsers.
Demo
If you are anything like me, you keep a close eye on the development of the variouscryptocurrencies. (In reality I very much do not because I love this planet, but,for the sake of this article, just assume Idid.) To keep track of the cryptocurrencies that I own, I have developed a web app that allows me towatch the markets in all life situations, such as from the comfort of my bed, where I have a decentsingle-screen setup.

This being about crypto, the markets can get hectic at any time. Should this happen, I can quicklymove over to my desk where I have a multi-screen setup. I can click on any currency's window andquickly see the full details in a fullscreen view on the opposite screen. Below is a recent photo ofme taken during the lastYCY bloodbath. It caught mecompletely off-guard and left mewith my hands on my face.

You can play with thedemo embedded below, or see itssource code on glitch.
Security and permissions
The Chrome team has designed and implemented the Window Management API using the coreprinciples defined inControlling Access to Powerful Web Platform Features,including user control, transparency, and ergonomics. The Window Management API exposesnew information about the screens connected to a device, increasing the fingerprinting surface ofusers, especially those with multiple screens consistently connected to their devices. As onemitigation of this privacy concern, the exposed screen properties are limited to the minimum neededfor common placement use cases. User permission is required for sites to get multi-screeninformation and place windows on other screens. While Chromium returns detailed screen labels,browsers are free to return less descriptive (or even empty labels).
User control
The user is in full control of the exposure of their setup. They can accept or decline thepermission prompt, and revoke a previously granted permission via the site information feature inthe browser.
Enterprise control
Chrome Enterprise users can control several aspects of the Window Management API asoutlined in the relevant section of theAtomic Policy Groupssettings.
Transparency
The fact whether the permission to use the Window Management API has been granted isexposed in the browser's site information and is also queryable via the Permissions API.
Permission persistence
The browser persists permission grants. The permission can be revoked via the browser's siteinformation.
Feedback
The Chrome team wants to hear about your experiences with the Window Management API.
Tell us about the API design
Is there something about the API that does not work like you expected? Or are there missing methodsor properties that you need to implement your idea? Have a question or comment on the securitymodel?
- File a spec issue on the correspondingGitHub repo, or add your thoughts to an existingissue.
Report a problem with the implementation
Did you find a bug with Chrome's implementation? Or is the implementation different from the spec?
- File a bug atnew.crbug.com. Be sure to include as much detail as youcan, simple instructions for reproducing, and enter
Blink>Screen>MultiScreen
in theComponents box.
Show support for the API
Are you planning to use the Window Management API? Your public support helps the Chrometeam to prioritize features and shows other browser vendors how critical it is to support them.
- Share how you plan to use it on theWICG Discourse thread.
- Send a tweet to@ChromiumDev using the hashtag
#WindowManagement
andlet us know where and how you are using it. - Ask other browser vendors to implement the API.
Helpful links
- Spec draft
- Public explainer
- Window Management API demo |Window Management API demosource
- Chromium tracking bug
- ChromeStatus.com entry
- Blink Component:
Blink>Screen>MultiScreen
- TAG Review
- Intent to Experiment
Acknowledgements
The Window Management API spec was edited byVictor Costan,Joshua Bell, andMike Wasserman.The API was implemented byMike Wasserman andAdrienne Walker. This article was reviewed byJoe Medley,François Beaufort,andKayce Basques. Thanks to Laura Torrent Puig for the photos.
Except as otherwise noted, the content of this page is licensed under theCreative Commons Attribution 4.0 License, and code samples are licensed under theApache 2.0 License. For details, see theGoogle Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.
Last updated 2020-09-14 UTC.