Jump to >

Extension Static Media Files

Static Media Bundles

Extensions can define sets of CSS and JavaScript files that should be packaged and made available for use on a page. These are called “bundles,” and are listed in the extension class’s Extension.css_bundles and Extension.js_bundles attributes.

Each bundle has a name and a list of source files pertaining to that type of bundle. The format for a bundle is the same for CSS and JavaScript. Here’s an example:

class SampleExtension(Extension):
    css_bundles = {
        'default': {
            'source_filenames': (

    js_bundles = {
        'default': {
            'source_filenames': (
        'admin': {
            'source_filenames': (

A bundle can have any name. Bundle names will not conflict between extensions.

There’s one special bundle named “default”. If a “default” bundle is defined, it will appear on all pages without having to be manually loaded. This is a good place to put code you know will always need to execute, such as your JavaScript JSExtension subclass, or to place CSS overrides you want to apply to all pages.

A bundle may also define an output_filename, if it cares to specifically name it. This is the name that will be used for the combined file during packaging. If not provided, the file will be named based on the bundle name. Usually, you will not need to provide your own name.

Packaging Bundles

Static bundles are packaged along with your extension automatically. You don’t have to do anything special. You will, however, need some node.js dependencies in order to package static media bundles.

If you’re running Review Board 2.5.7+, these dependencies will be installed for you when you begin to build the package.

If you’re running an older version, you will need to manually install them yourself. First, make sure you have a modern version of node.js installed and then run:

$ sudo npm install -g less uglifyjs

Writing Static Media


Files listed in Extension.css_bundles can either be plain CSS files, or less (*.less) files.

Less is an extension of CSS that allows for variables, macros, calculations, conditionals, includes, and more. When used with your extension, these files will be automatically compiled to CSS for you.

We recommend using less over plain CSS files.

No matter which you use, you will want to take care to namespace your class names and IDs appropriately, in order to not conflict with rules from either Review Board or other extensions.

Including Review Board Styles

If you’re using less, you can reference definitions (variables and macros) from Review Board’s stylesheets by adding:

@import (reference) "@{STATIC_ROOT}rb/css/defs.less";

This will allow you to use any variable or macro we have defined. You can see the list by viewing the contents of reviewboard/static/rb/css/defs.less (and the contents of any files it includes) in the branch for the version you’re developing against.


JavaScript files have access to the Review Board JavaScript codebase, jQuery, Backbone.js, and other shipped libraries.

It is recommended that you namespace all the code in your JavaScript file, and wrap the file in a closure, as so:

(function() {

// Your code here.


This will ensure that your variables do not leak and interfere with other extensions or the Review Board codebase.

Loading Static Media

When creating a template for a TemplateHook, you may need to load one of your bundles. There are a couple of ways to do this: By using the apply_to option for a bundle, or by manually loading using template tags.

Applying To Specific Pages

You can make a bundle apply to specific pages by listing their URL names in the apply_to option in the bundle. This looks something like:

class SampleExtension(Extension):
    css_bundles = {
        'my-bundle': {
            'source_filenames': (
            'apply_to': [

There are a few useful predefined lists of URL names that might be useful to you:

URLs for all diff viewer pages.
URLs for the review request and diff viewer pages.
URLs for the file attachment review and diff viewer pages.

Some other common URL names you might want to use include:

The review request page itself.
The file attachment review UI pages (note that this will apply to all types of file attachments with review UIs!).
The My Account page.
The login page.
The user registration page.
The Dashboard page.

You can look at the Review Board codebase reference for all the URL names (they’ll be listed in the urls.py files).

Loading Using Template Tags

This can be done through the {% ext_css_bundle %} or {% ext_js_bundle %} or template tags by passing the extension variable (provided to your template) and the bundle name to load. For example:

{% load djblets_extensions %}

{% ext_css_bundle extension "my-css-bundle" %}
{% ext_js_bundle extension "my-js-bundle" %}


Any bundles named “default” will be loaded automatically. You won’t need to manually load them on the page.

If you need to reference a static file (such as an image), you can use the {% ext_static %} template tag:

{% load djblets_extensions %}

<img src="{% ext_static extension 'images/my-image.png' %}" />