Focus/blur methods and events

  1. The focus method
  2. The getAttention recipe (for popup)
  3. The onfocus event
  4. Cases when the onfocus doesn’t work
  5. The getAttention recipe (main window)
  6. Summary

Both checking if the window is focused and focusing on a window/tab is tricky.

That’s partially because the focus/blur event do not bubble, and partially because the browser window is a part of OS and JavaScript is not integrated with the OS window manager.

Also, the security is important here, because the JavaScript focus/blur may not override a user’s will.

Still, let’s find out what we can do and see the possible pitfalls.

In this section we assume you know the focus/focusin/blur events described in Focus/Blur: methods and events fairly well.

The focus method

The window.focus allows to focus on the window. Unlike DOM elements focus, it works differently in different operational systems and browsers.

Here is the code to test it.

setInterval(function() { window.focus() }, 1000)

Actually, there may be three effects.

  1. The window is unminimized if needed and shown on top. That usually happens when you call win.focus on a popup and the main window is active.
  2. The window title starts to flash. To see it in action, open this page in IE, run the code above and switch to another window.

    The browser will try to bring your attention by title flickering.

  3. No effect at all. The most interesting one. Open this page in Firefox/Win, run the code and minimize the window. The window.focus won’t work at all. Also you can run it in Opera and switch to another tab… Other cases are possible.

So, it’s not that simple. Anyway, that’s all JavaScript can do with the window.

Guaranteed unminimize and bring to top

If you are the one who really needs a guaranteed focus, there is only one guaranteed recipe.

The windows and tabs are OS/browser business. So you need a way to call OS methods. Java with OS native bindings will do. Different bindings for Windows, MacOS, KDE, Gnome. Such java applet should also be signed.

If you are making a corporative application and only target a single browser/OS (IE? Chrome? Firefox?), that could be easier. All these browsers support extensions mechanism which can talk to OS directly.

So, that’s doable. But read on and see if you really need it.

Luckily, the JavaScript also has the power over the window title which can be abused to bring the user’s attention to the window. See below.

The getAttention recipe (for popup)

How can we bring the visitor’s attention to the window in a reliable way?

One of the best tricks is to join the window.focus() with title flashing.

Check it out on the example below:

<script>
  var win = open('/','test','width=300,height=300')

  function getAttention(win) {
    win.focus()
    var i = 0
    var show = ['************', win.document.title]

    var focusTimer = setInterval(function() {  
      if (win.closed) {
        clearInterval(focusTimer)
        return
      }   
      win.document.title = show[i++ % 2]
    }, 1000)

    win.document.onmousemove = function() { 
      clearInterval(focusTimer) 
      win.document.title = show[1]
      win.document.onmousemove = null
    }
  }
</script>
  
<input type="button" onclick="getAttention(win)" value="getAttention(win)">

Run it and minimize the window. Then press the button labelled getAttention(win).

Now even if you minimize the window or switch away, the title will draw your attention by changing to '***' and back every second.

In the example above, document.onmousemove event is used to detect that the visitor finally focused on the window and stops the indication.

The onfocus event can be used too, but it’s much less reliable.

The onfocus event

The rewritten variant could use onfocus and is given below:

<script>
  var win = open('/','test','width=300,height=300')

  function getAttention(win) {
    if (win.closed) { 
      alert("window is closed, can't flicker")
      return
    }

    var i = 0
    var show = ['************', win.document.title]

    function stop() {
      clearInterval(focusTimer) 
      win.document.title = show[1]      
    }
 
    win.onfocus = function() { 
      stop()
      win.onfocus = null
    }
      
    var focusTimer = setInterval(function() { 
      if (win.closed) {
        clearInterval(focusTimer)
        return
      } 
     
      win.document.title = show[i++ % 2]
    }, 1000)

    win.focus()  
  }
</script>

<input type="button" onclick="getAttention(win)" value="getAttention(win)">

Note the additional closed checks in the example above. Manipulations with a closed window cause exceptions, the check helps to evade them.

Cases when the onfocus doesn’t work

It is possible that the window is focused, but window.onfocus is not triggered.

That’s particulary because *switching to the window does not equal focusing on it.

For example, if the cursor is on browser URL field, then the window is considered not focused.

Try this:

  • Run the getAttention example above in Chrome or IE (they don’t allow to disable location bar).
  • Put the cursor on the location bar of the popup.
  • Switch back to this window and press the button with getAttention(win).

You will see that altough the window actually is in foreground and you switched to it, the focus event doesn’t fire. There are other cases when switching to window doesn’t trigger window.onfocus, meet them by check the example in IE.

If the window is brought into focus by clicking on an input field, there will be no window.onfocus in IE. And no window.onfocusin too.

So, the reliable way is to set additional hooks on document.onfocusin for IE and on document.onfocus on capturing phase, because it doesn’t bubble for other browsers.

The document never lies. But it only receives focus if the user focused somewhere in the document: clicked on it or performed another action, not just saw it.

That’s why document.onmousemove can also be used here to detect activity.

The getAttention recipe (main window)

The code of getAttention for the main window is easier and shorter.

Run the example below and minimize the window or change the tab. Notice how it starts to bring your attention in a second.

function getAttention() {
  var i = 0
  var show = ['************', document.title]

  function stop() {
    clearInterval(focusTimer) 
    document.title = show[1]      
  }
 
  onfocus = function() { 
    stop()
    onfocus = null      
  }
      
  var focusTimer = setInterval(function() {      
    document.title = show[i++ % 2]
  }, 1000)

  focus()  
}

setTimeout(getAttention, 1000)

Same enhancement with tracking document events apply here also.

Summary

The focus/blur methods on a window are unreliable, because of an OS-level nature of a browser tab/window.

But there is a nice recipe of getting user’s attention by flickering title.

There are focus/blur events on a window. But because of a number of reasons (and we didn’t touch iframes yet!) they are unreliable also.

Use them together with document.focusin(IE)/capturing document.focus(other) and document.mousemove to track the real activity.

Also, keep in mind that there is no way to detect if a window is visible. Let’s say we detected a period of inactivity and paused page updates. But the user may still watch the unactive window somewhere on the screen. A nasty surprise eh? Good thing to have in mind before you get to implement something like that.

See also:

Tutorial

Donate

Donate to this project