Introducing Ractive.js

Rich Harris 30 December 2013 Comments

Ractive.js is used to create interactives, such as '<a href=''>Food game: How well do you know the world?</a>'
Ractive.js is used to create interactives, such as 'Food game: How well do you know the world?'

Originally posted on the Guardian developer blog

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:

1. Just use jQuery

var p = $('p');

function updateView (username, msgCount) {
  p.text('Hello ' + username + '! You have ' + msgCount + ' new messages.');

This is generally agreed to be a Bad Idea – mixing your templates and your logic will end in tears. What if a non-programmer needs to change the wording? They'll probably break something, that's what.

2. Target specific elements

  Hello <span id='username'></span>!
  You have <span id='msgCount'></span> new messages.
var usernameSpan = $('#username'),
  msgCountSpan = $('#msgCount');

function updateUserName (username) {

function updateMsgCount (msgCount) {

// initialise our view

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?

var body = $(body),
  // we're using Underscore templates here
  template = new _.template(templateStr);

function updateView (model) {
  var html = template({
    username: model.username,
    msgCount: model.msgCount


// initialise

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.

The above example, with Ractive, would go something like this:

<p>Hello {{username}}! You have {{msgCount}} new messages.</p>
var view = new Ractive({
  el: document.body,
  template: templateStr,
  data: model // contains our username and msgCount properties

function updateView (model) {

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:

<button id='activate'>Activate!</button>
<button id='deactivate'>Deactivate!</button>
$('#activate').on('click', function () {

$('#deactivate').on('click', function () {

But if you treat the HTML as a blueprint, you can bake the semantics of user interaction right into your template:

<button proxy-click='activate'>Activate!</button>
<button proxy-click='deactivate'>Deactivate!</button>
  activate: function () {
  deactivate: function () {

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
Interactive data visualisations are much easier to create with Ractive.js – no DOM event handling, no state management, no labyrinthine render methods


The development of Ractive was made possible, in part, by the Bill and Melinda Gates Foundation's support for the Guardian Global Development desk.

comments powered by Disqus