JavaScript Event Sheets

Every now and again, I find myself wishing that I could use something like the CSS selectors to apply some JavaScript to a load of different elements at once. For example, imagine that you had a handful of images that you wanted to implement rollovers on*. Commonly, you might have an image called, say, "foo.png", and the rollover image called "foo_on.png". With JS rollovers you need to attach an onmouseover and onmouseout handler to each image. If you've only got one image then you might do it like this:

<img src="roll.gif" id="rollfirst"

which would look like this: demonstration rollover image

If you need more than one image on a page to roll over, then a pretty common technique is to name your images specially (as I have done; the rollover version of myimage.gif is myimage_on.gif) and then have rollover and rollout functions which know how to "generically" roll over and roll out of an image:

<script type="text/javascript">
function rollover(imgID) {
  // get the image object we're referring to
  var thisimg = document.getElementById(imgID);
  // and add "_on" to its src
  thisimg.src = thisimg.src.replace(/(\.[a-z0-9]+)$/i,'_on$1');
function rollout(imgID) {
  // get the image object we're referring to
  var thisimg = document.getElementById(imgID);
  // and remove "_on" from its src
  thisimg.src = thisimg.src.replace(/_on(\.[a-z0-9]+)$/i,'$1');
. . .
<img src="roll.gif" id="roll"
<img src="roll2.gif" id="roll2"

which would work like this: demonstration rollover image demonstration rollover image

But this still involves adding something (whether it's a load of JavaScript or a call to a neat little encapsulated function) to every image that needs to roll over. Wouldn't it be nice if you could apply a JavaScript event handler to images, say, based on their class, with a CSS selector? So you'd want to do something like:

img.rollover {
  mouseover: rollover_handler;
  mouseout: rollout_handler;
. . .
<img src="roll.gif" class="rollover">
<img src="roll2.gif" class="rollover">

Like this, in fact: demonstration rollover image demonstration rollover image

The bit above which says:

img.rollover {
  mouseover: rollover_handler;
  mouseout: rollout_handler;

is part of a JavaScript Event Sheet. Essentially, it looks like a stylesheet, but instead of defining style properties on elements indicated by the selector, it defines event handlers. Inside a block of declarations, you specify an event that can occur on the object (common examples would be click, mouseover, mouseout) and then the name of a JavaScript function which should be attached as the event handler for that event to all elements indicated by the selector.

"But who cares?", I hear you crying. "JavaScript-based image rollovers are lame anyway!"

True enough. But you can attach all kinds of things rather conveniently here. Most of my unobtrusive DHTML scripts have a big section, done on document load, that walks through the DOM and attaches event handlers to specified elements. This would make that a lot easier; just add a JSES sheet* with, say, ul.aqtree3 in it to do the binding of event handlers.

How to do it

JSES sheets are linked to a page in the same way as CSS stylesheets: with a LINK tag. Just add a tag like:

<link rel="jses" href="test.jses">

to your pages. You also need to include the Javascript library to make it work, and the WebFX XmlExtras library:

<script src="jses.js" type="text/javascript"></script>
<script src="xmlextras.js" type="text/javascript"></script>


There are a few limitations with this technique.

Browser support
Because we have to go and fetch the external stylesheet ourselves, we need a browser that supports making requests for URLs from JavaScript. That's IE or Mozilla, currently. The Xml Extras library covers the differences between them, but browsers without some analogue to the XMLHttpRequest object just plain won't work.
Not inline
You can't embed JSES sheets into your HTML; they have to be external and linked with the LINK tag. This is because there's no <jses> tag like there are <style> and <script> tags, and we can't just make one up.
No remote hosting
The JSES sheet is retrieved by JavaScript, and therefore must be hosted on the same domain as the HTML page, owing to JavaScript's security restrictions.


As with a lot of this stuff, it was built by standing on the shoulders of giants. In particular, WebFX's XML Extras library and Simon Willison's getElementsBySelector were crucial. Thanks, guys!

Updated 2006-01-13 to use the corrected addEvent function.

Stuart Langridge, November 2003

kryogenix.org | other browser experiments