JavaScript Theme Functions in Drupal

Drupal has an extensive theming system which includes theme functions that can be overridden and an extensible template system. There is an expectation that all markup go through the theme system and it is considered a bug when that doesn't happen. Most of the talk surrounding this system focuses on the server side system and what we can do in PHP. But, that's not all there is to the theme system. Drupal provides a theme system for JavaScript as well. One with callbacks that can be overridden by themes, just like on the PHP side.

Theme Functions

The central function to the theme system is Drupal.theme(). It is the JavaScript counterpart to theme() and works in a similar manner to what theme() did in Drupal 6.

The first step is to define a JavaScript theme function within a modules JavaScript file, then Drupal.theme() can use it. To define a theme function simply create a new function in the Drupal theme prototype namespace like:

Drupal.theme.prototype.displayName = function(name, url) {
  return '<a href="' + url + '">' + name + '</a>';
}

Once this is done the function can be used like:

var name = "John Doe";
var url = "http://example.com";
var display = Drupal.theme('displayName', name, url);

Just like the Drupal 6 theme() function usage, the arguments minus the first one are passed to the theme function itself. The first argument is the name of the function in the Drupal.theme.prototype namespace.

Overriding Theme Functions in Themes

Not only does this system allow us to reuse theme functions as templates, it provides a mechanism for themes to override these theme functions. For example, a module defines a theme function like the one above and uses it. But, a theme wants to change the markup. The theme can define an override function like:

Drupal.theme.displayName = function(name, url) {
  return '<a href="' + url + '"><em>' + name + '</em></a>';
}

This theme function has a slightly different name. Drupal.theme is the namespace instead of Drupal.theme.prototype. The function name is the same as is the function argument signature.

When Drupal.theme() sees this override function it uses it instead of the one defined by the module.

What Should Go Through Theme Functions?

The obvious answer is that all markup should go through theme functions. But, there is more to front end presentation than CSS and markup. For example, animations. It's not uncommon for JavaScript to cause something to display. What if a theme wanted that to slide in rather than just show up in the page? This is not something you can accomplish via markup and CSS changes.

So, instead of thinking of these theme functions as a place for markup consider putting from end presentation in them. All of it. Drupal JavaScript theme functions are something we need to use more. It is the system we currently have and one we should embrace.

For more information on the topic please see the Drupal.org handbook page.