Backbone Marionette — Introduction to Marionette.js
In this tutorial, you will learn about Backbone Marionette. We cover key concepts, practical examples, and best practices to help you master this topic.
Marionette.js extends Backbone.js with higher-level abstractions for building scalable applications. It provides Application, Module, LayoutView, CollectionView, CompositeView, and a region management system that eliminates boilerplate and enforces consistent patterns.
What You'll Learn
You'll learn Marionette's key components, how it improves on raw Backbone, and when to use it. You'll build structured views with regions and learn application lifecycle management.
Why It Matters
Raw Backbone becomes repetitive at scale. Every View needs render, cleanup, and event management. Marionette provides these patterns out of the box, reducing code by 40-60% in large applications.
Real-World Use
A security operations center (SOC) dashboard with 50+ views uses Marionette to manage layout regions, nested views, and application lifecycle. The Application object initializes all modules, and LayoutViews manage the complex sidebar-main-panel structure.
flowchart LR
A[Marionette.Application] --> B[Module 1]
A --> C[Module 2]
A --> D[Module 3]
B --> E[LayoutView]
E --> F[Region: sidebar]
E --> G[Region: main]
E --> H[Region: footer]
G --> I[CollectionView]
I --> J[ItemView]
Installing Marionette
Marionette requires Backbone, Underscore, and jQuery.
npm install backbone.marionette backbone underscore jquery
// ES module import
import Backbone from 'backbone';
import Marionette from 'backbone.marionette';
The Application Object
Marionette.Application is the starting point. It manages initialization, modules, and global events.
var App = new Marionette.Application();
// Regions are placeholders for views
App.addRegions({
headerRegion: '#header',
mainRegion: '#main',
footerRegion: '#footer'
});
// Initializers run on app start
App.addInitializer(function(options) {
console.log('App initializing with:', options.config);
});
// Event handlers
App.on('start', function() {
console.log('App started');
// Show a view in a region
var MainView = Marionette.View.extend({
template: _.template('<h1>Dashboard</h1><div id="content"></div>')
});
App.mainRegion.show(new MainView());
});
// Start the application
App.start({ config: { theme: 'dark' } });
Expected output:
App initializing with: {theme: 'dark'}
App started
LayoutView — Region Management
LayoutView manages nested regions within a view.
var DashboardLayout = Marionette.LayoutView.extend({
el: '#app',
template: _.template(
'<header id="header"></header>' +
'<aside id="sidebar"></aside>' +
'<main id="content"></main>' +
'<footer id="footer"></footer>'
),
regions: {
header: '#header',
sidebar: '#sidebar',
content: '#content',
footer: '#footer'
}
});
var HeaderView = Marionette.View.extend({
template: _.template('<h1>Security Dashboard</h1>')
});
var SidebarView = Marionette.View.extend({
template: _.template(
'<nav>' +
'<a href="#alerts">Alerts</a>' +
'<a href="#reports">Reports</a>' +
'<a href="#settings">Settings</a>' +
'</nav>'
)
});
var layout = new DashboardLayout();
layout.render();
layout.getRegion('header').show(new HeaderView());
layout.getRegion('sidebar').show(new SidebarView());
console.log('Layout rendered with regions');
CollectionView — Rendering Collections
Marionette's CollectionView automatically renders a collection, creating a child view for each model.
var Alert = Backbone.Model.extend({
defaults: { severity: '', message: '', timestamp: '' }
});
var AlertView = Marionette.View.extend({
tagName: 'li',
template: _.template(
'<span class="severity-<%= severity %>"><%= severity.toUpperCase() %></span> ' +
'<span><%= message %></span> ' +
'<span><%= timestamp %></span>'
)
});
var AlertListView = Marionette.CollectionView.extend({
tagName: 'ul',
className: 'alert-list',
childView: AlertView
});
var alerts = new Backbone.Collection([
{ severity: 'critical', message: 'SQL injection', timestamp: '10:30:00' },
{ severity: 'warning', message: 'Failed login', timestamp: '10:35:00' },
{ severity: 'info', message: 'System update', timestamp: '10:40:00' }
]);
var listView = new AlertListView({ collection: alerts });
listView.render();
console.log(listView.el.outerHTML);
Expected output:
<ul class="alert-list">
<li><span class="severity-critical">CRITICAL</span> <span>SQL injection</span> <span>10:30:00</span></li>
<li><span class="severity-warning">WARNING</span> <span>Failed login</span> <span>10:35:00</span></li>
<li><span class="severity-info">INFO</span> <span>System update</span> <span>10:40:00</span></li>
</ul>
View Lifecycle in Marionette
Marionette views have explicit lifecycle methods: initialize, onRender, onDomRefresh, onBeforeDestroy, onDestroy.
var LifecycleView = Marionette.View.extend({
template: _.template('<p>Lifecycle demo</p>'),
initialize: function() {
console.log('1. initialize');
},
onRender: function() {
console.log('2. onRender — view added to DOM');
},
onDomRefresh: function() {
console.log('3. onDomRefresh — fully rendered');
},
onBeforeDestroy: function() {
console.log('4. onBeforeDestroy — cleanup starting');
},
onDestroy: function() {
console.log('5. onDestroy — cleanup complete');
}
});
var view = new LifecycleView();
view.render();
// Later, clean up
view.destroy();
Expected output:
1. initialize
2. onRender — view added to DOM
3. onDomRefresh — fully rendered
4. onBeforeDestroy — cleanup starting
5. onDestroy — cleanup complete
Behaviors — Reusable View Logic
Marionette Behaviors encapsulate reusable view functionality.
var TooltipBehavior = Marionette.Behavior.extend({
onRender: function() {
this.view.$('[data-tooltip]').each(function() {
var $el = $(this);
$el.attr('title', $el.data('tooltip'));
});
}
});
var ConfirmBehavior = Marionette.Behavior.extend({
events: {
'click [data-confirm]': 'onConfirmClick'
},
onConfirmClick: function(e) {
if (!confirm(this.view.options.confirmMessage || 'Are you sure?')) {
e.preventDefault();
e.stopImmediatePropagation();
}
}
});
var DeleteButton = Marionette.View.extend({
template: _.template('<button data-confirm>Delete</button>'),
behaviors: {
tooltip: { behaviorClass: TooltipBehavior },
confirm: { behaviorClass: ConfirmBehavior, confirmMessage: 'Delete this item?' }
}
});
console.log('Behaviors provide reusable view logic');
Common Mistakes
- Not calling
render()on LayoutViews before accessing regions. Regions are not available until the layout is rendered. Calllayout.render()beforelayout.getRegion('header'). - Using
onShowinstead ofonRender.onShowis deprecated. UseonRenderandonDomRefreshfor lifecycle hooks. - Overriding
renderinstead of using template. Marionette calls render automatically. Override it only if you need custom rendering logic. - Not cleaning up regions when destroying a LayoutView. Calling
layout.destroy()does NOT automatically empty child regions. Uselayout.emptyRegions()first. - Creating a new Application instance per page. Use one Application. Marionette.Application is a Singleton that manages the entire app lifecycle.
Practice Questions
- What does Marionette.Application provide over plain Backbone?
- How do regions work in a LayoutView?
- What is the difference between CollectionView and CompositeView?
- What are Behaviors used for?
- Challenge: Create a Marionette application with a LayoutView containing three regions. Show a CollectionView in the main region. Add a Behavior that logs all view events. Verify lifecycle methods fire in order.
FAQ
Mini Project
Build a Marionette application with a LayoutView (header, sidebar, content, footer regions). Create a CollectionView for a list of alerts in the content region. Add a Behavior that highlights critical severity alerts with a red background. Use region management to swap views.
What's Next
Now that you understand Marionette, learn Backbone Testing for testing strategies. Then explore Backbone Debugging for debugging techniques.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro