Introducing Ractive.js: next-generation DOM manipulation

Anyone with fond memories of the sound of dial-up internet will understand how ridiculous it would have seemed, to the web's pioneers, that we would one day be using this geeky information exchange format to play games, do grocery shopping, collaborate on spreadsheets and even build more webapps. Yet here we are.

But despite taking over the world, the web has a dirty secret: it's actually a lousy platform for creating many of the experiences we take for granted. Let me qualify that: it's an amazing technology for creating documents, but for creating apps - interactive experiences that respond to user input, and represent changing data - web development can be akin to pulling teeth.

Consider the following simple task. We have an interface that shows our user, Dave, how many unread messages he has. When he gets a new message, how do we update the interface?

<p>Hello Dave! You have 4 new messages.</p>

In the bad old days, you'd have to reload the page, and the server would send you some freshly-rendered HTML. But let's assume we've got a model that contains our data, and that we need to update the existing view. Here are our options:

Better, except that now we've added two extra <span> elements to the DOM. That means more work for the browser, which can become particularly noticeable on mobile devices. And we've got to traverse the DOM and store references to elements.

3. Templating

<p>Hello <%= username %>! You have <%= msgCount %> new messages.</p>

Now we're getting somewhere - our templates and our logic are cleanly separated. But wait! What happens when we update the view?

What happens is that the existing element gets removed from the DOM, and a new one gets created. At best, the old one will be hoovered up by the garbage collector; at worst, it will remain in memory. Either way, it's bad for performance.

In the context of this contrived example it might seem trivial, but as an app becomes more complex, these things start to show.

4. Just use Angular

At this point, many developers will point you towards a framework such as AngularJS or EmberJS. These frameworks do a lot of the heavy lifting for you, particularly as far as model-view data binding is concerned.

Angular in particular is hugely popular at the moment. (The Guardian is currently using it for a major internal project, in fact.)

But these frameworks also have a cost - they tend to be fairly large, and once you've finished the 'hello world' tutorials they have steep learning curves. Particularly for smaller projects, it's often a case of using a sledgehammer to crack a nut.

You see the problem. What should be an incredibly basic task is a snakepit of compromises and ugly code - yet we're all so used to developing this way that we're barely even aware of how awkward it is.

Enter Ractive.js

Ractive was initially created to tackle the data binding problem in a more elegant way. We on the Guardian interactive team are acutely aware of the challenges of creating app-like experiences on the web; interactives, by their nature, require a huge amount of DOM manipulation, and as slaves to the editorial agenda we typically have tight deadlines.

Initially, Ractive parses the template and determines that '{{msgCount}}' should be treated as a separate text node, which depends on the 'msgCount' property of our model.

When you call 'view.set()', Ractive compares the new data against its current state, and scans its internal dependency graph to see if any part of the DOM needs to be updated. If so, it only touches those parts - which means no DOM nodes will be created or destroyed.

The browser has much less work to do, but - and this is the crucial part - so does the developer. The benefits of this approach become increasingly apparent as you deal with more complex templates, representing more complex data. You can see for yourself how it makes life easier by following the tutorials or checking out the examples.

Beyond data binding

It soon became apparent that this approach enables us to do other things more efficiently as well. It's a philosophical change in the relationship between HTML and JavaScript - HTML is no longer an inert substance which must have life breathed into it, but a blueprint for an app that is interactive by default.

Take event handling for example. Web developers are used to peppering their HTML with meaningless 'id' and 'class' attributes as 'hooks', so that they can later traverse the DOM, find them, and add event handlers:

Moreover, we can now automatically take care of things like reusing event handlers and automatically unbinding them when they're no longer needed. Event delegation becomes unnecessary. As with data binding, this approach prevents your code from becoming unwieldy as your app grows.

Sexy features

So far, this all sounds fairly prosaic - handy, perhaps, but nothing you can't already do with vanilla JS. But the real fun starts when we start exploiting some of the features that emerge from Ractive's statefulness and dependency tracking, such as complex but easy-to-create animations. We're one step closer to the holy grail of completely declarative, reactive programming.

But we're only getting started. While it's been used in production in several interactives, it's still an early-stage project which needs brave souls to try it out in projects and (if necessary!) submit bug reports. If you build something with it, we'd love to hear from you.

Interactive data visualisations are much easier to create with Ractive.js - no DOM event handling, no state management, no labyrinthine render methods