Progressive enhancement with handlers and enhancers

Recently I adopted a different way to manage bits of JavaScript in websites I was building. It exercises progressive enhancement (PE) by declaring handler and enhancer functions on HTML elements.

TL;DR: When JavaScript is used to handle user interactions like clicks, or enhance the page by manipulating the DOM, traditionally you’d have JavaScript find that HTML element in your page, and hook some code into it. But what if you’d switch that around, and have the HTML element “tell” JavaScript what function to execute?

How? I declare JavaScript functions on HTML elements. Separating them to functions that happen on click and those that happen on page load, I use two attributes (data-handler and data-enhancer) that both get space-separated function names as their values. Then, with a little bit of JavaScript, I make sure the functions execute when they need to.

Note that this works best for websites for which the mark-up is rendered on the server, to which JavaScript is added as an extra layer. Websites that rely on JavaScript for rendering content will probably have options to do the same within the framework they are built with.

Separating to handlers and enhancers

On many small to medium sized websites, the required JavaScript can be drilled down to two types of usage:

  1. things that need to happen on a click
  2. enhancements after the inital page load

Surely, there are often other events we want to use for triggering JavaScript (scroll, anyone?), but let’s focus on these two types first.

Many simple websites will have both types of script in a single scripts.js file, which is also used to query the nodes interactions need to happen on, and to add click handlers to those nodes.

This year, Krijn and Matijs introduced me to a new way to go about this. It has proven to be a very powerful pattern in some of my recent projects, which is why I’d like to share it here. Credits for the pattern, and for the initialisation functions I will discuss later, go to them.

Including JavaScript functions to the declarative model

The pattern starts from the idea that web pages have three layers to them: structure (HTML), lay-out (CSS) and enhancement (JavaScript). HTML is a declarative language: as an author, you declare what you’d like something to be, and that is what it will be.

Let this be a header, let this be a list item, let this be a block quote.

This is great, browsers can now know that ‘this’ is a list item, and treat it as such. Screenreaders may announce it as a list, your RSS reader or mobile Safari “reader view” can view it as a list, et cetera.

With CSS we declare what things look like:

Let headers be dark blue, let list items have blue bullets and let block quotes render in slightly smaller type.

This works rather well for us, because now we don’t need to think about what will happen if we add another list item. It being a list item, it will have the CSS applied to it, so it will have blue bullets.

The idea I’d like to share here, is that of making JavaScript functions part of this declarative model. If we can declare what something looks like in HTML, why not declare what its behaviour is, too?

Handlers: things that happen on a click

The idea is simple: we introduce a data-handler attribute to all elements that need to trigger function execution. As their value, we add one or more functions name(s) that need(s) to execute on click.

For example, here’s a link:

<a href="#punk-ipa">More about Punk IPA</a>

This is an in-page link to a section that explains more about Punk IPA. It will work regardless of JavaScript, but can be improved with it.

Cooler than linking to a section about Punk IPA, is to have some sort of overlay open, with or without a fancy animation. We add a data-handler attribute:

<a href="#punk-ipa" data-handler="overlay">More about Punk IPA</a> 

In the data-handler, the value holds a function name, in this case ‘overlay’. The idea is that the overlay function executes when the link is clicked. Naturally, you would be able to add more than one function name, and separate function names by spaces. This works just like class="foo bar".

Within the function declaration, we will know which element was clicked, so we can access attributes. We can access the href or any data attribute. With that, it can grab the content that’s being linked to, append it into some sort of overlay, and smoothly transition the overlay into the page.

Note that this is similar to doing <a onclick="overlayfunction(); anotherfunction();"> , but with the added benefit that a data-handler only gets meaning once JavaScript is active and running, and that it contains strings like CSS classes, instead of actual JavaScript code. This way, the scripting is separated in the same way as the style rules are.

Also note that is best practice to only add handlers to HTML elements that are made for click behaviour, like

Comments, likes & shares

No webmentions about this post yet! (Or I've broken my implementation)