Skip to content

Backbone Views — Rendering Data to the Screen

DodaTech Updated 2026-06-28 5 min read

In this tutorial, you will learn about Backbone Views. We cover key concepts, practical examples, and best practices to help you master this topic.

Backbone Views are responsible for rendering data to the DOM. They manage a single DOM element (el), bind to Models or Collections, render templates, and handle user interactions. Views are the bridge between data and interface.

What You'll Learn

You'll learn how to define Views, bind them to Models, render templates, manage the el property, and structure View hierarchies for complex UIs.

Why It Matters

Views keep UI logic separate from data logic. A Model does not care how it is displayed. A View does not care how data is stored. This separation makes code testable, maintainable, and easier to debug.

Real-World Use

A security dashboard has multiple Views: an AlertListView renders the alert collection, an AlertDetailView shows a single alert's details, and a FilterView manages search and filter controls. Each View operates independently.

flowchart LR
    A[Model] -->|change event| B[View.render]
    B --> C[Template]
    C --> D[DOM element]
    D -->|user action| E[View event]
    E -->|set| A

The el Property

Every View has an el — a reference to a DOM element. You can create a new element or reference an existing one from the page.

var TaskView = Backbone.View.extend({
  // Create a new element
  tagName: 'li',
  className: 'task-item',
  id: 'task-1',

  render: function() {
    this.$el.html('<span>Task Content</span>');
    return this;
  }
});

var view = new TaskView();
console.log('Tag:', view.el.tagName);
console.log('Class:', view.el.className);
console.log('ID:', view.el.id);

view.render();
$('#app').append(view.el);

Expected output:

Tag: LI
Class: task-item
ID: task-1

Binding Views to Models

A View typically binds to a Model or Collection and re-renders when data changes.

var Task = Backbone.Model.extend({
  defaults: { title: '', completed: false }
});

var TaskView = Backbone.View.extend({
  tagName: 'li',
  className: 'task-item',

  initialize: function(options) {
    this.model = options.model;
    // Re-render when model changes
    this.model.on('change', this.render, this);
  },

  render: function() {
    this.$el.html(
      '<input type="checkbox" ' +
      (this.model.get('completed') ? 'checked' : '') +
      '> ' +
      this.model.get('title')
    );
    return this;
  }
});

var task = new Task({ title: 'Learn Backbone', completed: false });
var view = new TaskView({ model: task });
view.render();

console.log('Rendered HTML:', view.el.outerHTML);

Expected output:

Rendered HTML: <li class="task-item"><input type="checkbox"> Learn Backbone</li>

Using Templates

Backbone does not include a templating engine. Underscore's _.template is the most common choice.

var Task = Backbone.Model.extend({
  defaults: { title: '', completed: false, priority: 'medium' }
});

var TaskView = Backbone.View.extend({
  tagName: 'li',
  className: 'task-item',

  // Underscore template
  template: _.template(
    '<input type="checkbox" <%= completed ? "checked" : "" %>> ' +
    '<span class="<%= priority %>"><%= title %></span>'
  ),

  initialize: function(options) {
    this.model = options.model;
    this.model.on('change', this.render, this);
  },

  render: function() {
    var html = this.template(this.model.toJSON());
    this.$el.html(html);
    return this;
  }
});

var task = new Task({
  title: 'Write documentation',
  completed: true,
  priority: 'high'
});

var view = new TaskView({ model: task });
view.render();
console.log('Template output:', view.el.outerHTML);

Expected output:

Template output: <li class="task-item"><input type="checkbox" checked> <span class="high">Write documentation</span></li>

Rendering Collections

A Collection View renders a list by creating child Views for each Model.

var Task = Backbone.Model.extend({
  defaults: { title: '' }
});

var TaskView = Backbone.View.extend({
  tagName: 'li',
  render: function() {
    this.$el.text(this.model.get('title'));
    return this;
  }
});

var TaskListView = Backbone.View.extend({
  tagName: 'ul',
  id: 'task-list',

  initialize: function(options) {
    this.collection = options.collection;
    this.collection.on('add', this.addOne, this);
    this.collection.on('reset', this.render, this);
  },

  render: function() {
    this.$el.empty();
    this.collection.each(function(task) {
      this.addOne(task);
    }, this);
    return this;
  },

  addOne: function(task) {
    var view = new TaskView({ model: task });
    this.$el.append(view.render().el);
  }
});

var tasks = new (Backbone.Collection.extend({ model: Task }))([
  { title: 'Task A' },
  { title: 'Task B' },
  { title: 'Task C' }
]);

var listView = new TaskListView({ collection: tasks });
listView.render();

console.log(listView.el.outerHTML);

Expected output:

<ul id="task-list"><li>Task A</li><li>Task B</li><li>Task C</li></ul>

View Lifecycle: initialize and remove

The initialize method sets up the View. The remove method cleans up — removes the DOM element and unbinds events.

var TimerView = Backbone.View.extend({
  tagName: 'div',

  initialize: function() {
    this.count = 0;
    this.interval = setInterval(function() {
      this.count++;
      this.$el.text('Count: ' + this.count);
    }.bind(this), 1000);
    console.log('Timer started');
  },

  remove: function() {
    clearInterval(this.interval);
    console.log('Timer cleaned up');
    Backbone.View.prototype.remove.call(this);
  }
});

var view = new TimerView();
$('#app').html(view.render().el);

// After 3 seconds, remove the view
setTimeout(function() {
  view.remove();
}, 3000);

Expected output (immediate):

Timer started

Expected output (after 3 seconds):

Timer cleaned up

View Events: Declarative Event Binding

Use the events property to bind DOM events declaratively.

var TaskView = Backbone.View.extend({
  tagName: 'li',

  events: {
    'click .delete': 'removeTask',
    'click .toggle': 'toggleComplete'
  },

  initialize: function() {
    this.template = _.template(
      '<span class="toggle"><%= title %></span> ' +
      '<button class="delete">Delete</button>'
    );
  },

  render: function() {
    this.$el.html(this.template(this.model.toJSON()));
    return this;
  },

  toggleComplete: function() {
    this.model.set('completed', !this.model.get('completed'));
  },

  removeTask: function() {
    this.model.destroy();
    this.remove();
  }
});

This View responds to clicks without manual jQuery binding. The events hash handles delegation automatically.

Common Mistakes

  1. Forgetting return this in render(). Backbone convention returns this from render() to enable chaining. The View is unusable in parent views without it.
  2. Not calling remove() on parent Views. Removing a parent View without calling remove() on child Views causes memory leaks from orphaned event listeners.
  3. Using inline HTML instead of templates. Hardcoding HTML in the View makes it hard to change. Use Underscore templates or separate template files.
  4. Binding events in render() instead of events hash. Binding in render() creates duplicate listeners on every render. Use the events hash for DOM events.
  5. Forgetting to pass {model: model} in initialize. The View needs a reference to its Model. Always pass options through the constructor.

Practice Questions

  1. What does the el property represent in a Backbone View?
  2. Why should render() return this?
  3. How do you clean up a View when it is no longer needed?
  4. What is the advantage of using the events hash over jQuery event binding?
  5. Challenge: Create a CollectionView that renders a list of models, supports adding new items, and removes items on click. Use event delegation for efficiency.

FAQ

Can a View have multiple DOM elements?

A View manages one el. For multiple elements, use nested Views.

How do I reference jQuery within a View?

Use this.$el for the View element or this.$(selector) to search within it.

What is the difference between `el` and `$el`?

el is the raw DOM element. $el is a jQuery wrapped version of the same element.

Can I use a different template engine?

Yes. Backbone does not require Underscore templates. Use Handlebars, Mustache, or any engine.

When is `render()` called?

You call render() manually. It does not run automatically on model changes — you must bind it in initialize().

Mini Project

Build a ContactListView that renders a collection of contacts (name, email, phone). Each contact has a ContactView with click-to-expand details. Include an addContact form View. Wire everything together in a main AppView.

What's Next

Now that you understand Views, learn Backbone View Events for detailed event handling. Then explore Backbone View Rendering for advanced rendering patterns.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro