We were unable to load Disqus. If you are a moderator please see our troubleshooting guide.

John • 12 years ago

the demo page is not working anymore.

I want to know how to use onbeforeunload event.

Marc Casavant • 9 years ago

If you're looking to use this to test for onbeforeunload support in chrome it won't work. The reason is that if you test the window object for .onunload support (hoping to find that it does support it so you can just write one event handler for all browsers) you will find it returns true for onunload. This is because it is a property on the window object. Only problem it has either been broken, or disabled. The reason you would want onunload is because it's an event that reliably fires on all apple and android devices and onbeforeunload only fires on chrome and Mozilla I believe. So in any case though when you set up your conditional event handler you're going to be hitting the wrong case in situations like in chrome where it claims to support both technically.

Abantu Audio • 5 years ago

So would you have a check for all mobile and desktop browsers? Or would you just use the onunload option for all browser types? From your post it seems that "onbeforeunload" should be used for chrome and Mozilla and "onunload" for android and apple mobile?

Karthikeyan • 12 years ago

Is there any way we could check the composition events i.e compositionstart , compositionend.

Max • 8 years ago

I'm not sure that it can be work with touch devices... events such as touchstart touchend etc...
I guess there should be something most stable way for checking the events.

Jan • 10 years ago

Excellent! Thanks!!

Peter Valdemar Mørch • 10 years ago

Update: I've written on stackoverflow about my suggestion for reliable beforeunload detection. It isn't perfect, but it works.

Peter Valdemar Mørch • 10 years ago

Hi,

Thanks for all your hard work.

FYI, especially about beforeunload:

This page has function isEventSupported(eventName), whereas the simple test case page has the more elaborate / different / newer function isEventSupported(eventName, element).

beforeunload does not work in Mobile Safari on iOS, even though isEventSupported('beforeunload', window) says it is supported. onbeforeunload doesn't fire reliably on mobile safari, where 'onbeforeunload' in window is true.

Peter

David • 10 years ago

The isEventSupported function does not work as expected with Android Chrome version 18. (Tested with the ontouchstart event.)

Twg • 11 years ago

Very nice article. Thank you for this.

kangax • 12 years ago

@John
I fixed a link to demo page. Thanks for a catch.

Troy III • 12 years ago

@John

"onbeforeunload" in window
>> true [IE, Fx, Ch, Sa]
>> false [Op] //still not supported!

will work...

********************************************************************************************************

But the true reason I'm posting this, is the fact that I wanted to Thank Kagnax for publishing this fundamentally important article, which as it seems have had a highly positive impact on our browser vendor world.

Daniel Friesen • 12 years ago

@wes DOMContentLoaded is one of the events you don't need to bother testing if it exists. Since what you really want is to fire as soon as you can depending on what the browser supports, you just try to register everything there is and add some sort of window.isAlreadyLoaded when one has fired so that the later ones don't do anything.

wes • 12 years ago

is there a way to check if DOMContentLoaded is supported?
there is no html equivalent (.ondomcontentloaded) in standard browsers!

Troy III • 12 years ago

This one, (considering the situation),is not that bad either:

isEventSupported =
function(El, ev){
El=document.createElement(El);El.setAttribute(ev,'');
El=typeof El[ev]=="function"; return El;
};

Yet creating elements just for the sake of the test is dirty as hell!

-Not sure if Divs support the "onreset" event...


isEventSupported("DIV", "onreset") //TRUE

...but, - it will at least mean that the browser supports it! :)
Have fun.

Troy III • 12 years ago

Contrary to other old static NN broods
IE was designed with dynamics in mind, and IE event model is amazing as always, if only other static born browsers would dare to follow - your code could become as short (simple, clean, efficient and powerfull) as this:

isEventSupported =
function(tag, event){
return document.createElement(tag)[event]===null;
};

example:

alert( isEventSupported("DIV", "onclick") ); //TRUE
alert( isEventSupported("DIV", "atclick") ); //FALSE

example:

if( isEventSupported("DIV", "onclick") ){..[if true code]..}else{..[if false code]..}

(For a range of other Window events not covered by Document object, one could use the IFRAME element)

This (code) works on Explorer, because the default value of supported events is "null" and of course "undefined" for those which are not.

[the cons.] Regretfully:
- only Explorer provides the means for this.
- It will also return TRUE for events it can recieve - but cannot fire.
------------------------------------
On Firefox[5], the finite list of event names (and properties) exposed on "Event object" are the following:

CAPTURING_PHASE
AT_TARGET
BUBBLING_PHASE
MOUSEDOWN
MOUSEUP
MOUSEOVER
MOUSEOUT
MOUSEMOVE
MOUSEDRAG
CLICK
DBLCLICK
KEYDOWN
KEYUP
KEYPRESS
DRAGDROP
FOCUS
BLUR
SELECT
CHANGE
RESET
SUBMIT
SCROLL
LOAD
UNLOAD
XFER_DONE
ABORT
ERROR
LOCATE
MOVE
RESIZE
FORWARD
HELP
BACK
TEXT
ALT_MASK
CONTROL_MASK
SHIFT_MASK
META_MASK

to close useless, one might say.

Johan Sundström • 12 years ago

More data on a corner case of this: IE 9 supposedly supports the "onload" event for <script src="..."> tags, in IE9 Standards Mode (at least according to EricLaw -MSFT-), but on pages that don't live up to whatever that means, it does not fire. Unfortunately, however, testing for the event support with the tricks outlined here always detects it as supported:
hasEvent(document.createElement('script'), 'onload'); // always true in IE9 :-(

function hasEvent(el, onFoo) {
if (onFoo in el) return true;
// Gecko fallback:
el.setAttribute(onFoo, '');
var ok = 'function' === typeof el[onFoo];
el.removeAttribute(onFoo);
return ok;
}
I haven't come up with any tidy hack to detect this without resorting to user agent sniffing, I'm afraid.

André • 12 years ago

Hello,
I tried your function to detect support for "webkitTransitionEnd", "oTransitionEnd" and "transitionend". In all browsers I tested your function the result was "false", although they support css3 transitions.

Greetings

-André-

Diego Perini • 13 years ago

Robin,
if you read a few messages above you see I suggested a method to detect "oninput" event support on Firefox.
Later I observed that all new HTML5 events and many others can be tested in all browsers by creating a disconnected "BODY" element, assigning attributes to it, then check if the same-name property on the "window" object is a "function" reference instead of a "string":

var test = "oninput";
var body = document.createElement("body");
body.setAttribute(test, "return");

if (window[test] && window[test].call) {
alert("Event is supported !");
}

this kind of testing could destroy previously installed handlers, so save/restore them before/after testing.
Unfortunately I believe this is just a cross-browser bug that has to be fixed, so relying on it seems risky at best.

Mathias Bynens • 13 years ago
Robin • 13 years ago

There are now some extra events included with HTML5, like "input" [http://goo.gl/UiE19] which fires as soon as information is input into a form element.

Unfortunately while "input" works in Chrome 8 and Fx 4b7, it seems very hard to detect support for. It is not included in the Event object in either browser:

'INPUT' in Event // returns false

In Chrome, the event can be detected by the script, I assume because it *does* register a "oninput" method on the element. However, Firefox doesn't seem to, so even though Firefox supports "input" it can't be detected by any method we have here.

If anyone has any ideas on this please comment, I'd really like to solve this.

Paul Grenier • 13 years ago

I've found a problem with dispatching several events in Chrome and as a result I also have to sniff the browser as you suggested (see http://code.google.com/p/pr...

In case you're interested, I think the problem stems from Chrome's JIT compilation of the JS into machine code--it must see a string of events dispatching each other as a single call stack, and as a result, the call stack size is exceeded. In every other browser, dispatching an event clears the stack. My workaround right now is to have Chrome dispatch the event using setTimeout() which clears the stack as expected (but takes longer).

Timothy Stone • 14 years ago
The only oddity I noticed with this method was IE reporting false for “unload” event. “unload” can still be easily checked in a global window object – "unload" in window – returns true in all versions of IE that I tested (6-8). That expression can, of course, produce false positives if there’s a global “unload” variable, but, as a workaround, you can always try deleting the variable and see if in still returns true.

You should be able fix this "problem" with a theoretical, but typical of cut-and-paste javascript, global "unload" property by calling "hasOwnProperty" in the check of the element.

Deleteing the variable could lead to other problems that could be silent killers of code.

Daniel Friesen • 14 years ago

@Diego Perini
Interesting, I never thought of trying to indirectly trigger events that way.
I did do some experimentation with dispatchEvent when I was trying to come up with a method myself. I was dispatching input events directly, then realized that would work whether or not input events were supported.
I was of the impression that there was no strange magic behind the scenes that would cause events to implicitly trigger other events when an event was faked by user code.

I'm already checking what browsers support oninput (it looks like Chrome supports it as well, normal tests work too) I'll come up with the least intrusive way to use your trick to check for support and probably make a blog post of my findings as well.

Diego Perini • 14 years ago

Daniel,
you haven't tried hard enough ... it is actually possible to detect if the browser can trigger "input" events for keystrokes in "input" controls.

To simulate real user interaction on the control you have to combine setting ".focus()" and then ".dispatch()" a "keypress" event on the element you want to test.

The difficult step will be recognizing browsers that implements "KeyEvents" or "KeyboardEvents" interfaces and create/init the correct event appropriately.

Daniel Friesen • 14 years ago

Interesting however I noticed that Firefox 3.5 actually supports html5's oninput however so far every detecion method I try here fails at detecting support for it.

Anton Stoychev • 14 years ago

Can anyone tell me whether it can detect proprietary events? I'm trying to develop a slightly future proof web application to support multi-touch interactivity but to do so I have to recognise the machine as such. So far I think only firefox 3.7 support multi-touch events.

onMozMagnifyGestureStart
onMozMagnifyGestureUpdate
onMozMagnifyGesture
onMozRotateGestureStart
onMozRotateGestureUpdate
onMozRotateGesture
onMozTapGesture
onMozPressTapGesture
onMozTouchDown
onMozTouchMove
onMozTouchRelease


Can anyone with multi-touch device can confirm that isEventSupported return true on these events, with firefox 3.7 multi-touch build? It returns false with windows XP and FF 3.7 multi-touch build. I couldn't find any multi-touch emulator to test it on my machine.
I've browsed through the patch's code and so far I can only test whether such event exist in a browser but not if it is supported by the device:

typeof MozTouchEvent != 'undefined'
typeof SimpleGestureEvent != 'undefined'


This tests whether the event model exists.
Mark "Tarquin" Wilton-Jonesstates that models as well may be tested via

document.implementation.hasFeature('EventModelName','2.0') || window.EventModelName 


Having looked at examples of firefox multitouch these events are attached to document. It may be that they can be attached only onto document node but there's no clear specification.

kangax • 14 years ago

@Rob Reid

The reason isEventSupported was failing "unload", is because it had to be tested on window object (as you rightfully noticed). In Mozilla, however, "onunload" in window is false, so fallback inference of setting an attribute has to be used (which works reliably so far):

var el = document.createElement('div');
el.setAttribute('onunload', '');
typeof el.onunload == 'function'; // true

I modified a snippet slightly. It now falls back on performing setAttribute-based check on generic element.

Thanks for bringing it up.

kangax • 14 years ago

@marcis

"beforeunload" can also be inferred with in (in supporting browsers) — 'onbeforeunload' in window is true in my WebKit (nightly). Firefox doesn't support that kind of inference, but allows to detect "beforeunload" be setting corresponding attribute on an element — just like described in a post (even though it might seem weird):


var el = document.createElement('div');
el.setAttribute('onbeforeunload', '');
typeof el.onbeforeunload; // "function"
jpv • 14 years ago

thanks for this detection tip, I used it to detect if the browser does support the XHR onprogress event, here is the code :

if(sFeatureName == 'xhr-event-progress') {
var oEl = new XMLHttpRequest();
if(!oEl) // if standard XHR does not exist, we're probably on IE6 that do not support event progress anyway
return false;
return ('onprogress' in oEl);
}

Note that the test on the function type for FF is not mandatory here since it's not a DOM element
usage is situation (french) : http://jpv.typepad.com/blog...

marcis • 14 years ago

What about "beforeunload" event for window object?

Rob Reid • 14 years ago

Great function! Just what I was looking for the other day.

I have tweaked it slightly to add a test in for resize/unload so that IE/Webkit report on this correctly.

http://www.strictly-softwar...

Doing a test for resize/unload and then setting the element variable to a window reference instead of creating an element dynamically didn't seem to work in Opera causing failure reports. So I just check for unload/resize after your initial test and that seems to work across browsers.

var isEventSupported = (function(){
var win=this, //ta john!
cache={}, //cache results
TAGNAMES = {
'select':'input','change':'input',
'submit':'form','reset':'form',
'error':'img','load':'img','abort':'img'
};
function isEventSupported(eventName) {
var key = (TAGNAMES[eventName] || (eventName=="unload"||eventName=="resize")?"window":'div') + "_" + eventName;
if(cache[key])return cache[key];
var el = document.createElement(TAGNAMES[eventName] || 'div');
var oneventName = 'on' + eventName.toLowerCase();
// this test should work in most cases apart from IE/Webkit with unload/resize
var isSupported = (oneventName in el);
// we cannot use createElement to create a window object so to get a correct test for IE/Webkit on resize/unload check the window
if(!isSupported && (eventName=="unload" || eventName=="resize")){
isSupported = (oneventName in win);
}
// fallback to setAttribute if supported
if (!isSupported && el.setAttribute) {
el.setAttribute(oneventName, 'return;');
isSupported = typeof el[oneventName] == 'function';
}
// the above tests should work in majority of cases but this test checks the EVENT object
// haven't seen an example where this is required yet so may not be needed.
if(!isSupported && win.Event && typeof(win.Event)=="object"){
isSupported = (eventName.toUpperCase() in win.Event);
}
el = null;
cache[key]=isSupported;
return isSupported;
}
return isEventSupported;
})();
Tiong • 14 years ago

This is definitely one of the best tutorial i ever came across with. Nice tip, thanks for shaing with us.

David Mark • 15 years ago

"The only oddity I noticed with this method was IE reporting false for “unload” event"

Not that odd as "unload" causes a test on a DIV.

Also, you are assuming that all browsers that fail the initial - in - test have a working setAttribute method. Looks like a good inference for now and the foreseeable future, but it is not the best approach.

Diego Perini • 15 years ago

@kangax,
isn't that just the "Gecko" based browser you use that doesn't support event names on the Event Prototype ?

All Firefox and Netscape versions I could test up to Mozilla 1.7 have support for that bit of info !

Opera is what makes our testing harder here.

kangax • 15 years ago

I uploaded another test page which checks names through both - original and Diego's versions - for comparison.
It appears that Gecko 1.8 (e.g. Firefox 2) doesn't have uppercased event names in global Event object, so all tests return false :/

@John
Interesting, indeed. Will play with it more.

John Resig • 15 years ago

An interesting technique. It's also interesting to note that this technique also works for determining if event bubbling will work correctly. For example checking for the change event on a div returns false in IE but true in Firefox.

Diego Perini • 15 years ago

@Juriy,
"ContextMenu" like "DOMContentLoaded", "DOMActivate", "DOMFocusIn", DOMFocusOut" and Mutation Events are not exposed as properties like other DOM0 events.

I believe it will be hard to find such old informations since this fact was known already in early versions of Netscape 4, available when setting up capturing of events with the old API:

window.captureEvents( Event.MOUSEMOVE | Event.MOUSEOVER | Event.CLICK );

This is a link which contains a few info on the subject, also not exhaustive:

https://developer.mozilla.o...

So if we leave out for a moment "contextmenu" and Mutation/DOM events the code can probably be shortened a bit.

kangax • 15 years ago

@Radoslav, @Lea - Thanks, guys!

@Diego
Interesting. I wasn't aware of this. Looking at Firefox, Event does indeed have keys corresponding to uppercased events - "MOUSEMOVE" in Event; // true, and the values seem to be - 2^n - 1,2,4,8,16...

Interesting that some events - e.g. "contextmenu" - are not present.

I also couldn't find any mention of such properties in DOM L2 Event specs. Could you point me to where you've seen them?

Diego Perini • 15 years ago

Very useful stuff indeed, as always here...

FYI Mozilla, Firefox, Safari, Konqueror (and derivated browsers) have had event names enumerated on their own "Event" object for a while, I believe it is a W3C recommendation/specification, maybe useful for your testing and shorter code too.

Lea Verou • 15 years ago

Awsome article!!
I've tried to detect DOM L2 events myself in the past, but always got stuck in the firefox issue.
Thanks!

Radoslav Stankov • 15 years ago

I didn't know about this technique, it always great to learn new stuff. 10x for sharing