Learn how to integrate Handlebars with Express.js to create dynamic, server-side rendered HTML pages. This tutorial guides you through setting up Handlebars, creating templates, and passing data from Express to Handlebars for efficient content rendering.



What is Handlebars?

Handlebars is a templating engine that allows you to build reusable HTML templates. Known for its simplicity, Handlebars uses {{ ... }} expressions to bind data into templates, making it straightforward to render HTML on the server. When combined with Express.js, Handlebars can dynamically render content based on data passed from the backend, creating a flexible and customizable user experience.

Install Express and Handlebars

To get started, ensure that Node.js is installed. Then, create a new Express project and add the required dependencies:

npm init -y
npm install express express-handlebars

Configure Handlebars as the View Engine in Express

In your main server file (often app.js or server.js), configure Express to use Handlebars as its templating engine.

const express = require('express');
const exphbs = require('express-handlebars').create(); // Ensure compatibility with latest versions
const app = express();

// Set up Handlebars as the templating engine
app.engine('handlebars', exphbs.engine);
app.set('view engine', 'handlebars');

// Specify a custom directory for Handlebars views (optional)
app.set('views', __dirname + '/views');

// Serve static files
app.use(express.static('public'));

// Pass global data to all templates
app.use((req, res, next) => {
    res.locals.siteName = 'Your Company';
    next();
});

Handlebars Project Structure

Here's an example structure for an Express project using Handlebars, with directories for templates, reusable partials, and static assets:

express-handlebars-app/
├── views/
│   ├── partials/            # Reusable templates like headers or footers
│   │   ├── header.handlebars
│   │   └── footer.handlebars
│   └── pages/               # Individual page templates
│       ├── home.handlebars
│       ├── items.handlebars
│       └── products.handlebars
├── public/                  # Static files (CSS, JS, images)
│   ├── css/
│   ├── js/
│   └── images/
└── app.js                   # Main application file

Create Handlebars Templates

Inside the views/pages directory, create a template file (home.handlebars):

<!-- views/pages/home.handlebars -->
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{{title}}</title>
    <link rel="stylesheet" href="/css/styles.css">
</head>

<body>
    {{> header}}

    <h1>{{message}}</h1>
    <p>This is a dynamic page rendered with Handlebars and Express.js.</p>

    {{> footer}}
</body>

</html>

In this template, {{title}} and {{message}} are dynamic values passed from Express to Handlebars.

Handlebars Syntax Basics

Handlebars uses simple expressions and blocks to render data and perform basic logic.

  • Plain Text: Anything outside {{ ... }} is rendered as regular HTML.
  • Dynamic Variables: {{variable}} inserts a dynamic value from Express.
    <h1>{{title}}</h1>
    
  • Conditionals: Use {{#if}} and {{else}} for conditional rendering.
    {{#if user}}
      <p>Welcome, {{user.name}}!</p>
    {{else}}
      <p>Please log in.</p>
    {{/if}}
    
  • Loops: Use {{#each}} to loop over arrays and render each item.
    <ul>
      {{#each items}}
        <li>{{this}}</li>
      {{/each}}
    </ul>
    

Passing Data from Express to Handlebars

In Express, use res.render() to pass data to a Handlebars template. The data is passed as an object, and all key-value pairs in the object become accessible in the template.

app.get('/', (req, res) => {
    res.render('pages/home', {
        title: 'Welcome',
        message: 'Dynamic content with Handlebars and Express!'
    });
});

Using JavaScript Logic in Handlebars

Handlebars allows basic logic, such as conditionals and loops, directly in templates.

// Define a route for items
app.get('/items', (req, res) => {
    const items = ['Laptop', 'Smartphone', 'Tablet'];
    res.render('pages/items', { items });
});

In items.handlebars:

<!-- views/pages/items.handlebars -->
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Items List</title>
</head>

<body>
    <h1>Items:</h1>
    <ul>
        {{#each items}}
            <li>{{this}}</li>
        {{/each}}
    </ul>
</body>

</html>

Reusable Partials

Handlebars supports partials, which are reusable components that make it easy to keep code organized. Partials are useful for elements like headers, footers, or navigation bars.

Creating Partials

To create reusable header and footer components, add two .handlebars files in the partials directory:

  1. Header Partial (header.handlebars):
    <!-- views/partials/header.handlebars -->
    <header>
      <nav>
        <a href="/">Home</a>
        <a href="/about">About Us</a>
      </nav>
    </header>
    
  2. Footer Partial (footer.handlebars):
    <!-- views/partials/footer.handlebars -->
    <footer>
      <p>© 2024 Your Company</p>
    </footer>
    

Using Partials in Main Templates

To include a partial in a template, use the {{> partialName}} syntax.

<!-- views/pages/home.handlebars -->
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>{{title}}</title>
</head>

<body>
    {{> header}}

    <h1>Main Content</h1>
    <p>Welcome to our dynamic page rendered with Handlebars and Express.js.</p>

    {{> footer}}
</body>

</html>

With this setup, the header.handlebars and footer.handlebars partials are automatically included in any template that references them, helping to keep your code organized and manageable.

Complete Example

Here's how to combine everything into a simple product catalog:

Setting Up app.js

Create an Express server in app.js, set up Handlebars as the templating engine, define sample data, and create a route to display a list of products.

const express = require('express');
const exphbs = require('express-handlebars');
const app = express();

// Set up Handlebars as the templating engine
app.engine('handlebars', exphbs());
app.set('view engine', 'handlebars');

// Route to render the home page
app.get('/', (req, res) => {
    res.render('pages/home', { title: 'Welcome', message: 'Dynamic content with Handlebars and Express!' });
});

// Route to render a list of items
app.get('/items', (req, res) => {
    const items = ['Laptop', 'Smartphone', 'Tablet'];
    res.render('pages/items', { items });
});

// Sample product data for product catalog
const products = [
    { id: 1, name: 'Laptop', price: 75000 },
    { id: 2, name: 'Smartphone', price: 50000 },
    { id: 3, name: 'Tablet', price: 35000 }
];

// Route to render the products page
app.get('/products', (req, res) => {
    res.render('pages/products', {
        title: 'Product Catalog',
        products: products
    });
});

// Start the server on port 3000
app.listen(3000, () => {
    console.log('Server running on http://localhost:3000');
});

Creating the products.handlebars Template

In the views/pages directory, create a products.handlebars file to display the product catalog. Use partials for the header and footer to keep the template organized.

<!-- views/pages/products.handlebars -->
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>{{title}}</title>
</head>

<body>
    {{> header}}

    <main>
        <h1>{{title}}</h1>
        <div class="products">
            {{#each products}}
                <div class="product">
                    <h2>{{name}}</h2>
                    <p>Price: ₹{{price}}</p>
                </div>
            {{/each}}
        </div>
    </main>

    {{> footer}}
</body>

</html>

Conclusion

In this tutorial, you've learned how to set up and configure Handlebars as a templating engine in Express.js, create and render dynamic HTML pages, pass data from Express to Handlebars, and use basic JavaScript logic in templates with loops, conditionals, and partials. With this knowledge, you can now build data-driven, server-side rendered applications with flexible and reusable content.



Found This Page Useful? Share It!
Get the Latest Tutorials and Updates
Join us on Telegram