How to detect when a tab is focused or not in Chrome with Javascript?
Asked Answered
P

7

78

I need to know if the user is currently viewing a tab or not in Google Chrome. I tried to use the events blur and focus binded to the window, but only the blur seems to be working correctly.

window.addEventListener('focus', function() {
  document.title = 'focused';
});

window.addEventListener('blur', function() {
  document.title = 'not focused';
});

The focus event works weird, only sometimes. If I switch to another tab and back, focus event won't activate. But if I click on the address bar and then back on the page, it will. Or if I switch to another program and then back to Chrome it will activate if the tab is currently focused.

Pearce answered 27/4, 2010 at 11:20 Comment(5)
Did you try to attach those events to docment instead of window?Jim
I'm not sure whether it affects event detection, but the window.focus action is disabled (or at least buggy) in Chrome. See here and here for more.Equipage
Doesn't work with document either and this is for the focus event, not the focus action. I think I'll change my approach to this and change the event to either mouseover or window scrolling. For this scenario it's appropriate.Pearce
The code you in the question works perfectly in Chrome as of 2011. The solution does not work.Scuppernong
possible duplicate of Is there a way to detect if a browser window is not currently active?Hydroxyl
S
140

2015 update: The new HTML5 way with visibility API (taken from Blowsie's comment):

document.addEventListener('visibilitychange', function(){
    document.title = document.hidden; // change tab text for demo
})

The code the original poster gives (in the question) now works, as of 2011:

window.addEventListener('focus', function() {
    document.title = 'focused';
});

window.addEventListener('blur', function() {
    document.title = 'not focused';
});

edit: As of a few months later in Chrome 14, this will still work, but the user must have interacted with the page by clicking anywhere in the window at least once. Merely scrolling and such is insufficient to make this work. Doing window.focus() does not make this work automatically either. If anyone knows of a workaround, please mention.

Scuppernong answered 31/5, 2011 at 7:27 Comment(5)
The way to get this to work without the user having to click somewhere first is to add "window.focus()" to the window.onload event. The side effect of this is that if the window is the target of a link and was already open behind the current window, it's going to be brought to the front. Note that this solution only detects loss of focus, not that it was caused by switching tabs. For example, if loss of focus was due to the user clicking inside an iframe, you have to eliminate that:Maunder
<iframe ... onmouseover="iframeMouse(true)" onmouseout="iframeMouse(false)"></iframe>Maunder
function iframeMouse(over) { oif = over; } window.addEventListener('blur', function() { document.title = oif ? "iframe focused" : "not focused"; });Maunder
For a more in-depth robust answer see this. forums.greensock.com/topic/…Nilsanilsen
Use document.visibilityState to get current visibility stateCarborundum
H
8

The selected answer for the question Is there a way to detect if a browser window is not currently active? should work. It utilizes the Page Visibility API drafted by the W3C on 2011-06-02.

Heteromerous answered 12/7, 2012 at 13:54 Comment(0)
E
2

It might work after all, i got curious and wrote this code:

...
setInterval ( updateSize, 500 );
function updateSize(){
  if(window.outerHeight == window.innerHeight){
    document.title = 'not focused';             
  } else {
    document.title = 'focused';
  }

  document.getElementById("arthur").innerHTML = window.outerHeight + " - " + window.innerHeight;
}
...
<div id="arthur">
  dent
</div>

This code does precisly what you want, but on an ugly way. The thing is, Chrome seems to ignore the title change from time to time (when switching to the tab and holding the mouse down for 1 sec seems to always create this effect).

You will get different values on your screen, yet your title won't change.

conclusion: Whatever you are doing, don't trust the result when testing it!

Enhance answered 27/4, 2010 at 12:13 Comment(2)
The title changes instantly for me. If I change the events to mouseover and mouseout I get instant results.Pearce
Anyway, thanks for the (window.outerHeight == window.innerHeight) part. For this particular project I only need to know if the user is currently focused or not. No need to constantly check, and your code works.Pearce
P
2

For anyone who wants to swap page titles on blur and then go back to the original page title on focus:

// Swapping page titles on blur
var originalPageTitle = document.title;

window.addEventListener('blur', function(){
    document.title = 'Don\'t forget to read this...';
});

window.addEventListener('focus', function(){
    document.title = originalPageTitle;
});
Playlet answered 29/9, 2015 at 18:45 Comment(0)
W
0

I found that adding onblur= and onfocus= events to inline bypassed the issue:

Wager answered 30/1, 2012 at 7:40 Comment(0)
I
0

This could work with JQuery

$(function() {
    $(window).focus(function() {
        console.log('Focus');
    });

    $(window).blur(function() {
        console.log('Blur');
    });
});
Inquest answered 12/7, 2012 at 7:14 Comment(1)
I think this will not help because as he reported browser does NOT fire event function you have attached in 'blur'. So as in your example and code console.log('Blur'); will NOT be called in some situations.Hefner
F
-2

In chrome you can run a background script with a timeout of less than 1 second, and when the tab does not have focus chrome will only run it every second. Example;

This doesn't work in Firefox or Opera. Don't know about other browsers, but I doubt it works there too.

var currentDate = new Date();
var a = currentDate.getTime();

function test() {
    var currentDate = new Date();
    var b = currentDate.getTime();
var c = b - a;
    if (c > 900) {
        //Tab does not have focus.
    } else {
        //It does
    }
    a = b;
    setTimeout("test()",800);
}



setTimeout("test()",1);
Fortunio answered 17/3, 2012 at 11:0 Comment(1)
I don't like the idea of using intervals for something that should be evented. And note, you should be using setTimeout(test, 800). If you give it a string, it will eval() it, which is much much slower.Pearce

© 2022 - 2024 — McMap. All rights reserved.