65

How can I detect if a user is switching to another browser tab?

Currently, I have this:

$(window).on("blur focus", function (e) {

    var prevType = $(this).data("prevType");

    if (prevType != e.type) { //  reduce double fire issues
        switch (e.type) {
            case "blur":
                $('.message').html('<div class="alert alert-error">Oops. You navigated away from the ads <a id="start" class="butt green">Resume</a></div>');

                var myDiv = $("#bar");
                myDiv.clearQueue();
                myDiv.stop();
                clearInterval($timer);
                $timer = null;
                break;
            case "focus":
                // do work
                break;
        }
    }

    $(this).data("prevType", e.type);
});

But that only works when the user is minimizing the active window.

Denys Séguret
  • 372,613
  • 87
  • 782
  • 758
oliverbj
  • 5,771
  • 27
  • 83
  • 178

5 Answers5

175

Now we can use the visibility API.

To deal with the different browser-specific syntaxes, I made this small code :

var vis = (function(){
    var stateKey, eventKey, keys = {
        hidden: "visibilitychange",
        webkitHidden: "webkitvisibilitychange",
        mozHidden: "mozvisibilitychange",
        msHidden: "msvisibilitychange"
    };
    for (stateKey in keys) {
        if (stateKey in document) {
            eventKey = keys[stateKey];
            break;
        }
    }
    return function(c) {
        if (c) document.addEventListener(eventKey, c);
        return !document[stateKey];
    }
})();

Usage :

var visible = vis(); // gives current state

vis(aFunction);      // registers a handler for visibility changes

Example :

vis(function(){
  document.title = vis() ? 'Visible' : 'Not visible';
});

Demonstration page

Denys Séguret
  • 372,613
  • 87
  • 782
  • 758
  • 1
    thank you, but I cannot out your code in angularjs. it not working – John Nguyen Jan 29 '15 at 01:59
  • 3
    @Ali.NET I use it on all browsers – Denys Séguret Jun 11 '15 at 08:42
  • In Firefox 41 (Linux) it doesn't work as desired. If I switch the browser tab, it works ok. If I minimize the browser window it works too. But if I switch to another app, it doesn't work. The ``document.hidden `` property remains ``false`` even if another window is active. – pumbo Oct 02 '15 at 07:38
  • 1
    @pumbo Yes, the visibility API, right now, doesn't make it always possible to know if another application is hiding the browser. I don't think there's currently a way to get that information. – Denys Séguret Oct 02 '15 at 07:49
  • @DenysSéguret "window focus/blur" method can detect if the user switched to another window – pumbo Oct 02 '15 at 08:21
  • @pumbo I just checked: if another window goes front and hides the browser, the "blur" event isn't triggered (ubuntu/chromium) – Denys Séguret Oct 02 '15 at 08:58
  • @DenysSéguret I repeated the test in Firefox 41, Opera 12.16, Chrome 43 and the "blur" event is always triggered on my system (OS Debian 8). Maybe this behaviour is OS specific. – pumbo Oct 05 '15 at 03:19
  • Is it possible to implement this when close the tab? @DenysSéguret – Mehmet Kagan Kayaalp Mar 29 '16 at 12:34
  • @waterkinq What do you mean ? If you want to act on tab closing it's a different matter (and you should avoid it, as it's not reliable and will only be worse). – Denys Séguret Mar 29 '16 at 12:48
  • @DenysSéguret I want to logout from the site automatically when I close the tab or browser. I mean when I logout the site by closing the tab instead of using logout button, after entering the URL again, I want to logout from the site to force the user to enter username and password again. – Mehmet Kagan Kayaalp Mar 29 '16 at 12:51
  • Here it is my question and I tried to use Visible API by looking at this answer: http://stackoverflow.com/questions/36283638/logout-when-the-user-close-the-tab @DenysSéguret – Mehmet Kagan Kayaalp Mar 29 '16 at 13:05
  • Not possible? I was waiting an answer from you @DenysSéguret if it is possible please :/ I have searched it and tried it for a while but still I did not find an answer in Visibility API. Why I can handle switching tabs event but not closing the tab event? If it is not possible, I afraid I will try to find something else to solve my problem :/ If is possible, can you show an example please. – Mehmet Kagan Kayaalp Mar 31 '16 at 17:39
  • 2
    @waterkinq There's no reliable way to take action on tab/browser closing. It's a design choice (the situation was different 5 years ago). It means you must *never* rely on being notified by the browser of a disconnection, you must handle it properly server side. – Denys Séguret Mar 31 '16 at 17:58
  • Consider this solution: [visibilityState ][1] [1]: https://stackoverflow.com/a/10328781/4572425 – Dudi Oct 02 '17 at 13:06
  • hi @Denys Séguret, many thanks for your answer. I have a question on the same, I start a timer when user tabs out and check the timer when user comes back, I start the timer something like this ``` if(vis() == true) { currentRequest = Date.now(); seconds = parseInt((currentRequest-lastRequest)/1000); } else { lastRequest = Date.now(); } ``` but see that the time results don't seem to work correctly, i only reports time for one of the tabs correctly. Can you please suggest what can i do to make it work for tabs scenario? – opensource-developer Jul 22 '19 at 09:24
29

These 3 lines of code worked for me

document.addEventListener("visibilitychange", function() {
      document.title = document.hidden ? "I'm away" : "I'm here";
});
      

reference link: document.hidden

demo: https://iamsahilralkar.github.io/document-hidden-demo/

Sahil Ralkar
  • 2,331
  • 23
  • 25
  • Also see https://developer.mozilla.org/en-US/docs/Web/API/Document/visibilitychange_event which suggests checking for 'pagehide' as well – Marcus Feb 01 '21 at 20:59
  • 2
    It's now recommended to use [document.visibilityState](https://developer.mozilla.org/en-US/docs/Web/API/Document/visibilityState) instead of [document.hidden](https://developer.mozilla.org/en-US/docs/Web/API/Document/hidden). – Greg Dec 10 '21 at 08:47
  • How do I update a local variable in angular with this ? Say I have a local variable, userOnPage, I want to set it to true or False. When I do this.userOnPage = document.hiden, I get the following error: property 'userOnPage' does not exist on type document – alpha027 May 22 '22 at 11:20
9

If you want to detect whether the tab is visible to the user, use document.visibilityState to perform the check (a read-only property). Although document.hidden works too, as others have written, then W3C considers it 'historical' and recommends using the former approach.

If you only want to know whether the tab is active, use document.hasFocus() to perform the check. In this case, the tab could still otherwise be visible, but not active (e.g. two parallel view browser windows, where only one is active, both visible).

If you want capture the change to the state of visibility (and naturally also the active state in this case), then listen to the visibilitychange event from the Page Visibility API.

Example using all three

// Capture change to visibility
document.addEventListener("visibilitychange", function() {
    // Check if tab content is visible
    if (document.visibilityState) { 
        console.log("Tab is visible!") 
    }

    // Check if tab is active
    if (document.hasFocus()) {
        console.log("Tab is active!");
    }
});

Handling browser compatibilities

You can set up the following checks to cover incompatible browsers.

Note: Does not include hasFocus() as it's compatible all the way to IE6.

var visibilityState, visibilityChange;
if (typeof document.visibilityState !== "undefined") {
    visibilityState = "visibilityState";
    visibilityChange = "visibilitychange";
} 
else if (typeof document.mozVisibilityState !== "undefined") {
    visibilityState = "mozVisibilityState";
    visibilityChange = "mozvisibilitychange";
} 
else if (typeof document.msVisibilityState !== "undefined") {
    visibilityState = "msVisibilityState";
    visibilityChange = "msvisibilitychange";
} 
else if (typeof document.webkitVisibilityState !== "undefined") {
    visibilityState = "webkitVisibilityState";
    visibilityChange = "webkitvisibilitychange";
}

if (visibilityChange != null && visibilityState != null) {
    document.addEventListener(visibilityChange, function() {
        if (document[visibilityState]) { 
            console.log("Tab is visible!") 
        }
    }, false);
}

Quick MDN references

danefondo
  • 525
  • 7
  • 15
7

CASE 1

Just add this EventListener in your constructor.

document.addEventListener("visibilitychange", function() {
      if (document.hidden) {
        //do whatever you want
        console.log("Hidden");
      }
      else {
        //do whatever you want
        console.log("SHOWN");
      }
});

CASE 2

See here If you change tab $(window).blur(function () function will call and If you again come to this tab $(window).focus(function () function will call. Add this code in your constructor

$(window).focus(function () {
      //do something
       console.log("You are in this tab");
});

$(window).blur(function () {
      //do something
       console.log("You left this tab");
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<p>Click here and click outside of this..</p>
Rohit Tagadiya
  • 3,373
  • 1
  • 25
  • 25
4

This is an ES6 multi-browser-solution which I use to determine the tab visibility. I took inspiration from Deny's solution and tailored it to my needs.

const vis = (c) => {
  let self = this
  const browserProps = {
    hidden: "visibilitychange",
    msHidden: "msvisibilitychange",
    webkitHidden: "webkitvisibilitychange",
    mozHidden: "mozvisibilitychange",
  }
  for (item in browserProps) {
    if (item in document) {
      eventKey = browserProps[item]
      break
    }
  }

  if (c) {
    if (!self._init && !(typeof document.addEventListener === "undefined")) {
      document.addEventListener(eventKey, c)
      self._init = true
      c()
    } 
  }
  return  !document[item] 
}

vis(() => {
  let tabVisibility = vis() ? 'Visible' : 'Not visible';
  console.log(tabVisibility)
})
Hexodus
  • 12,361
  • 6
  • 53
  • 72