Detect If Browser Tab Has Focus

JavascriptOptimizationPolling

Javascript Problem Overview


Is there a reliable cross-browser way to detect that a tab has focus.

The scenario is that we have an application that polls regularly for stock prices, and if the page doesn't have focus we could stop the polling and save everyone the traffic noise, especially as people are fans of opening several tabs with different portfolios.

Is window.onblur and window.onfocus an option for this?

Javascript Solutions


Solution 1 - Javascript

Yes, window.onfocus and window.onblur should work for your scenario:

http://www.thefutureoftheweb.com/blog/detect-browser-window-focus

Solution 2 - Javascript

Surprising to see nobody mentioned document.hasFocus

if (document.hasFocus()) console.log('Tab is active')

MDN has more information.

Solution 3 - Javascript

Important Edit: This answer is outdated. Since writing it, the Visibility API (mdn, example, spec) has been introduced. It is the better way to solve this problem.


var focused = true;

window.onfocus = function() {
    focused = true;
};
window.onblur = function() {
    focused = false;
};

AFAIK, focus and blur are all supported on...everything. (see http://www.quirksmode.org/dom/events/index.html )

Solution 4 - Javascript

While searching about this problem, I found a recommendation that Page Visibility API should be used. Most modern browsers support this API according to Can I Use: http://caniuse.com/#feat=pagevisibility.

Here's a working example (derived from this snippet):

$(document).ready(function() {
  var hidden, visibilityState, visibilityChange;

  if (typeof document.hidden !== "undefined") {
    hidden = "hidden", visibilityChange = "visibilitychange", visibilityState = "visibilityState";
  } else if (typeof document.msHidden !== "undefined") {
    hidden = "msHidden", visibilityChange = "msvisibilitychange", visibilityState = "msVisibilityState";
  }

  var document_hidden = document[hidden];

  document.addEventListener(visibilityChange, function() {
    if(document_hidden != document[hidden]) {
      if(document[hidden]) {
        // Document hidden
      } else {
        // Document shown
      }

      document_hidden = document[hidden];
    }
  });
});

Update: The example above used to have prefixed properties for Gecko and WebKit browsers, but I removed that implementation because these browsers have been offering Page Visibility API without a prefix for a while now. I kept Microsoft specific prefix in order to stay compatible with IE10.

Solution 5 - Javascript

I would do it this way (Reference http://www.w3.org/TR/page-visibility/):

	window.onload = function() {
	
		// check the visiblility of the page
		var hidden, visibilityState, visibilityChange;

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


		if (typeof document.addEventListener === "undefined" || typeof hidden === "undefined") {
			// not supported
		}
		else {
			document.addEventListener(visibilityChange, function() {
		        console.log("hidden: " + document[hidden]);
		        console.log(document[visibilityState]);

		        switch (document[visibilityState]) {
		        case "visible":
		        	// visible
		            break;
		        case "hidden":
                    // hidden
		            break;
		        }
		    }, false);
		}

		if (document[visibilityState] === "visible") {
			// visible
		}
			
	};  

Solution 6 - Javascript

Posting this answer because I found a bug in accepted answer.

The bug is when you open a developer console on the focused window and click anywhere on it, the developer console has the focus now, at this point window.onfocus or window.onblur has no effect whatsoever.

So here is my solution,

document.addEventListener("visibilitychange", function() {
    if (document.visibilityState === 'visible') {
        console.log('has focus');
    } else {
        console.log('lost focus');
    }
});

Read more https://developer.mozilla.org/en-US/docs/Web/API/Document/visibilitychange_event

Solution 7 - Javascript

> Cross Browser jQuery Solution! Raw available at GitHub

Fun & Easy to Use!

The following plugin will go through your standard test for various versions of IE, Chrome, Firefox, Safari, etc.. and establish your declared methods accordingly. It also deals with issues such as:

  • onblur|.blur/onfocus|.focus "duplicate" calls
  • window losing focus through selection of alternate app, like word
    • This tends to be undesirable simply because, if you have a bank page open, and it's onblur event tells it to mask the page, then if you open calculator, you can't see the page anymore!
  • Not triggering on page load

Use is as simple as: Scroll Down to 'Run Snippet'

$.winFocus(function(event, isVisible) {
	console.log("Combo\t\t", event, isVisible);
});

//  OR Pass False boolean, and it will not trigger on load,
//	Instead, it will first trigger on first blur of current tab_window
$.winFocus(function(event, isVisible) {
	console.log("Combo\t\t", event, isVisible);
}, false);

//  OR Establish an object having methods "blur" & "focus", and/or "blurFocus"
//	(yes, you can set all 3, tho blurFocus is the only one with an 'isVisible' param)
$.winFocus({
	blur: function(event) {
		console.log("Blur\t\t", event);
	},
	focus: function(event) {
		console.log("Focus\t\t", event);
	}
});

//  OR First method becoms a "blur", second method becoms "focus"!
$.winFocus(function(event) {
	console.log("Blur\t\t", event);
},
function(event) {
	console.log("Focus\t\t", event);
});

/*    Begin Plugin    */
;;(function($){$.winFocus||($.extend({winFocus:function(){var a=!0,b=[];$(document).data("winFocus")||$(document).data("winFocus",$.winFocus.init());for(x in arguments)"object"==typeof arguments[x]?(arguments[x].blur&&$.winFocus.methods.blur.push(arguments[x].blur),arguments[x].focus&&$.winFocus.methods.focus.push(arguments[x].focus),arguments[x].blurFocus&&$.winFocus.methods.blurFocus.push(arguments[x].blurFocus),arguments[x].initRun&&(a=arguments[x].initRun)):"function"==typeof arguments[x]?b.push(arguments[x]):
"boolean"==typeof arguments[x]&&(a=arguments[x]);b&&(1==b.length?$.winFocus.methods.blurFocus.push(b[0]):($.winFocus.methods.blur.push(b[0]),$.winFocus.methods.focus.push(b[1])));if(a)$.winFocus.methods.onChange()}}),$.winFocus.init=function(){$.winFocus.props.hidden in document?document.addEventListener("visibilitychange",$.winFocus.methods.onChange):($.winFocus.props.hidden="mozHidden")in document?document.addEventListener("mozvisibilitychange",$.winFocus.methods.onChange):($.winFocus.props.hidden=
"webkitHidden")in document?document.addEventListener("webkitvisibilitychange",$.winFocus.methods.onChange):($.winFocus.props.hidden="msHidden")in document?document.addEventListener("msvisibilitychange",$.winFocus.methods.onChange):($.winFocus.props.hidden="onfocusin")in document?document.onfocusin=document.onfocusout=$.winFocus.methods.onChange:window.onpageshow=window.onpagehide=window.onfocus=window.onblur=$.winFocus.methods.onChange;return $.winFocus},$.winFocus.methods={blurFocus:[],blur:[],focus:[],
exeCB:function(a){$.winFocus.methods.blurFocus&&$.each($.winFocus.methods.blurFocus,function(b,c){this.apply($.winFocus,[a,!a.hidden])});a.hidden&&$.winFocus.methods.blur&&$.each($.winFocus.methods.blur,function(b,c){this.apply($.winFocus,[a])});!a.hidden&&$.winFocus.methods.focus&&$.each($.winFocus.methods.focus,function(b,c){this.apply($.winFocus,[a])})},onChange:function(a){var b={focus:!1,focusin:!1,pageshow:!1,blur:!0,focusout:!0,pagehide:!0};if(a=a||window.event)a.hidden=a.type in b?b[a.type]:
document[$.winFocus.props.hidden],$(window).data("visible",!a.hidden),$.winFocus.methods.exeCB(a);else try{$.winFocus.methods.onChange.call(document,new Event("visibilitychange"))}catch(c){}}},$.winFocus.props={hidden:"hidden"})})(jQuery);
/*    End Plugin      */

// Simple example
$(function() {
	$.winFocus(function(event, isVisible) {
		$('td tbody').empty();
		$.each(event, function(i) {
			$('td tbody').append(
				$('<tr />').append(
					$('<th />', { text: i }),
					$('<td />', { text: this.toString() })
				)
			)
		});
		if (isVisible) 
			$("#isVisible").stop().delay(100).fadeOut('fast', function(e) {
				$('body').addClass('visible');
				$(this).stop().text('TRUE').fadeIn('slow');
			});
		else {
			$('body').removeClass('visible');
			$("#isVisible").text('FALSE');
		}
	});
})

body { background: #AAF; }
table { width: 100%; }
table table { border-collapse: collapse; margin: 0 auto; width: auto; }
tbody > tr > th { text-align: right; }
td { width: 50%; }
th, td { padding: .1em .5em; }
td th, td td { border: 1px solid; }
.visible { background: #FFA; }

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<h3>See Console for Event Object Returned</h3>
<table>
    <tr>
        <th><p>Is Visible?</p></th>
        <td><p id="isVisible">TRUE</p></td>
    </tr>
    <tr>
        <td colspan="2">
            <table>
                <thead>
                    <tr>
                        <th colspan="2">Event Data <span style="font-size: .8em;">{ See Console for More Details }</span></th>
                    </tr>
                </thead>
                <tbody></tbody>
            </table>
        </td>
    </tr>
</table>

Solution 8 - Javascript

This is 10 years old. Here is a newer version: https://stackoverflow.com/questions/52892889/pause-resume-css-animations-when-switching-tabs

Basicly use Mozillas Javascript https://developer.mozilla.org/en-US/docs/Web/API/Window/focus_event

 function pause() {

 //Do something

 }

 function play() {

 //Do something

 }
 window.addEventListener('blur', pause);
 window.addEventListener('focus', play);

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionFentonView Question on Stackoverflow
Solution 1 - JavascriptRyan WrightView Answer on Stackoverflow
Solution 2 - JavascriptaleclarsonView Answer on Stackoverflow
Solution 3 - JavascriptZirakView Answer on Stackoverflow
Solution 4 - JavascriptIlijaView Answer on Stackoverflow
Solution 5 - JavascriptconfileView Answer on Stackoverflow
Solution 6 - JavascriptShoyeb SheikhView Answer on Stackoverflow
Solution 7 - JavascriptSpYk3HHView Answer on Stackoverflow
Solution 8 - JavascripthumanView Answer on Stackoverflow