SHARE
Facebook X Pinterest WhatsApp

Detecting Browser Event Support

thumbnail Detecting Browser Event Support
Written By
thumbnail Rob Gravelle
Rob Gravelle
Aug 23, 2013

8/23/13

I can still remember the day that I discovered the Mouseover and Mouseout events and how they could be utilized to change images when the user hovered the mousepointer over them. I knew at that moment that my world would never be the same. Later, I came to know of other useful events, such as onload, onsubmit, and onclick. Eventually, I was even hooking up my own custom events using non-obtrusive JavaScript. It wasn’t as simple as registering for an event in the HTML tag, but there was only two event registration models: Internet Explorer’s and everyone else’s! There are a lot more native event types available nowadays, some of which are vendor-specific or only partially supported. Non-universally supported events include Internet Explorer’s mouseenter and mouseleave, as well as Opera’s contextmenu, onbeforepaste, onbeforecut, and afterupdate events, which are recognized by IE and WebKit, but not in Mozilla-based browsers. In those cases, it helps to be able to tell which browsers supports a given event. Ideally, the detection would not rely on browser sniffing, which hardly ever works. We’ll be looking at a few such techniques today.

Detecting Document-level Events

At its core, checking for an event is not unlike checking for supported properties. The idea is to use the in keyword to test the event name against the node’s attribute collection. This test returns a true or false value accordingly:

alert('onclick' in document.documentElement); //displays true

The part where it gets complicated is that you must perform the test on an element that could conceivably be the owner of that event. For example, the onchange event is not produced by the document element, so testing against it will always return false.

alert('onchange' in document.documentElement);        //displays false
alert('onchange' in document.createElement('input')); //displays true

Coding with this in mind, we can associate certain events with their triggering elements, such as submit and reset with the form element. Other events would apply to numerous element types, including the DIV, so it is used as the default. The function below incorporates an event-to-element object to create the correct test element. It also accepts events with or without the “on” prefix, in the jQuery style:

function isEventSupported(eventName) {
  var TAGNAMES = {
    'select': 'input',
    'change': 'input',
    'submit': 'form',
    'reset' : 'form',
    'error' : 'img',
    'load'  : 'img',
    'abort' : 'img'
  }
  eventName = eventName.replace(/^on/, '');
  var elt = document.createElement(TAGNAMES[eventName] || 'div');
  var eventIsSupported = ('on'+eventName in elt);
  elt = null;
  return eventIsSupported;
}

alert(isEventSupported('click'));    //true
alert(isEventSupported('onchange')); //true
alert(isEventSupported('splat'));    //false    

The “Firefox” Technique

Some browsers, such as Firefox, are known to create methods on an element when an attribute with the same name as a supported event is set on that element:

var elt = document.createElement('div');
alert('before: ' + (typeof elt.onclick));  //object

el.setAttribute('onclick', 'return;');
alert('after: ' + (typeof elt.onclick));   //function in Firefox, string in IE

elt.setAttribute('onclick2', 'return;');  
alert('after: ' + (typeof elt.onclick2));   //"undefined" in Firefox, string in IE

We can incorporate that feature into our function for even more robust operation:

//...
var elt = document.createElement(TAGNAMES[eventName] || 'div');
eventName = 'on'+eventName;
var eventIsSupported = (eventName in elt);
if (!eventIsSupported) {
  elt.setAttribute(eventName, 'return;');
  eventIsSupported = typeof elt[eventName] == 'function';
}
elt = null;
return eventIsSupported;
//...

Testing For Events on the Global Window Object

Certain events like onunload and onresize pertain exclusively to the global window object. We can add it to the element array, but we have to be careful in our handling of the window, since one cannot be created using createElement(). A ternary operator tests for out special ‘win’ element type so that elt points to the window object without the use of createElement():

  var TAGNAMES = {
    //...
    'unload': 'win', 
    'resize': 'win'
  }, eventIsSupported;
  eventName = eventName.replace(/^on/, '');
  var elt = TAGNAMES[eventName] == 'win' 
          ? window 
          : document.createElement(TAGNAMES[eventName] || 'div');
  eventName = 'on'+eventName;
  eventIsSupported = (eventName in elt);

Caching Results

Ideally you would want to save results to a variable for later reference, but, if you were to perform a check every time that an event fires, it might be useful to have caching going on within the method itself. That’s easy enough to do using a closure, so that the cache resides in memory between function calls. Here then is the entire function showing how the closure is created using an outer inline method call:

var isEventSupported = function() {
  var cache = {};
  
  return function(eventName) {
    var TAGNAMES = {
      'select': 'input',
      'change': 'input',
      'submit': 'form',
      'reset' : 'form',
      'error' : 'img',
      'load'  : 'img',
      'abort' : 'img',
      'unload': 'win', 
      'resize': 'win'
    },
    shortEventName = eventName.replace(/^on/, '');
    if(cache[shortEventName]) { return cache[shortEventName]; }
    var elt = TAGNAMES[shortEventName] == 'win' 
            ? window 
            : document.createElement(TAGNAMES[shortEventName] || 'div');
    eventName = 'on'+shortEventName;
    var eventIsSupported = (eventName in elt);
    if (!eventIsSupported) {
      elt.setAttribute(eventName, 'return;');
      eventIsSupported = typeof elt[eventName] == 'function';
    }
    elt = null;
    cache[shortEventName] = eventIsSupported;	
    return eventIsSupported;
  };
}();

alert(isEventSupported('click'));    //true
alert(isEventSupported('onchange')); //true
alert(isEventSupported('splat'));    //false
alert(isEventSupported('unload'));   //true
alert(isEventSupported('unload'));   //true (from cache)

Conclusion

I make no claims that this is the greatest event testing code ever written, but it does give you some idea as to what can be done to ascertain whether or not a given event is supported by the browser. Feel free to take what I’ve done here and use it as a starting point for your own development.

thumbnail Rob Gravelle

Rob Gravelle resides in Ottawa, Canada, and has been an IT guru for over 20 years. In that time, Rob has built systems for intelligence-related organizations such as Canada Border Services and various commercial businesses. In his spare time, Rob has become an accomplished music artist with several CDs and digital releases to his credit.

Recommended for you...

Best VR Game Development Platforms
Enrique Corrales
Jul 21, 2022
Best Online Courses to Learn HTML
Ronnie Payne
Jul 7, 2022
Working with HTML Images
Octavia Anghel
Jun 30, 2022
Web 3.0 and the Future Of Web Development
Rob Gravelle
Jun 23, 2022
HTML Goodies Logo

The original home of HTML tutorials. HTMLGoodies is a website dedicated to publishing tutorials that cover every aspect of being a web developer. We cover programming and web development tutorials on languages and technologies such as HTML, JavaScript, and CSS. In addition, our articles cover web frameworks like Angular and React.JS, as well as popular Content Management Systems (CMS) that include WordPress, Drupal, and Joomla. Website development platforms like Shopify, Squarespace, and Wix are also featured. Topics related to solid web design and Internet Marketing also find a home on HTMLGoodies, as we discuss UX/UI Design, Search Engine Optimization (SEO), and web dev best practices.

Property of TechnologyAdvice. © 2025 TechnologyAdvice. All Rights Reserved

Advertiser Disclosure: Some of the products that appear on this site are from companies from which TechnologyAdvice receives compensation. This compensation may impact how and where products appear on this site including, for example, the order in which they appear. TechnologyAdvice does not include all companies or all types of products available in the marketplace.