Cross-platform windows.onFocusChanged issues - How to check if no windows have focus? How to detect a minimize event?

According to the windows.onFocusChanged event documentation, it returns either the focused window’s ID, or -1 (windows.WINDOW_ID_NONE).

Will be windows.WINDOW_ID_NONE if all browser windows have lost focus.


In Windows and some Linux window managers, WINDOW_ID_NONE will always be sent immediately preceding a switch from one browser window to another.

meaning on some (most) OSes (e.g. Windows), a focus switch between windows fires this event twice, one returning -1 and the other a windowId. While on others (e.g. MacOS), only one is fired, returning windowId. And I suppose all OSes fire just one, returning -1, when no window has focus.

Given the need to check for these twin simultaneous events, what is the best way to detect each of these conditions on any platform?

  • A browser window is minimized
  • No browser window has focus
  • Both at once

Maybe you could ignore the callback values and query fresh data from the API.
I use something like this, but for a different use-case.

const allWindowns = (await => w.type ===;
const minimized = allWindowns.filter(w => w.state ===;

Thanks @juraj.masiar for that idea. I’ve come up with something using windows.getLastFocused() and manual tracking of focus instead:

(For brevity, = 'minimized' and = -1)

// Manually track which window has focus.
// This is how we find out which window was defocused and whether it was/is minimized.
const FocusedWindowId = {
    set: focusedWindowId =>{ focusedWindowId }),
    get: async () => (await'focusedWindowId')).focusedWindowId,

function handleDefocusedWindow(window) {
  console.log(`windowId ${} defocused ${window.state === 'minimized' ? 'and minimized' : ''}`);
} focusedWindowId => {

    // focusedWindowId is -1 when a window loses focus in Windows and some Linux window managers, or only when no window has focus in MacOS and others.
    // Hence when a window switch happens, this event is fired twice in Windows et al: from the defocused window (-1) and from the focused window.
    if (focusedWindowId === -1) {
        const lastFocusedWindow = await;
        if (lastFocusedWindow.focused) {
            // We are in Windows et al - the counterpart event capture will handle the focused window separately
        } else {
            console.log('No window is focused');

    const defocusedWindowId = await FocusedWindowId.get();
    const defocusedWindow = defocusedWindowId && await => null);
    if (defocusedWindow)


If you see any issues let me know!

1 Like

Looks interesting :slight_smile:.
The only issue I see is the persistent storage Why not store it in memory to avoid IO operation?

If you are targeting Firefox 115 and above (Firefox ESR 115 is out in 2 weeks), you can use

I didn’t know storage.session is now available! Thanks!