Express Template Partials
Introduction
When building web applications with Express.js, you'll quickly realize that many pages share common elements like headers, footers, navigation bars, and other UI components. Recreating these elements on every page leads to duplicate code, which violates the DRY (Don't Repeat Yourself) principle.
Template partials solve this problem by allowing you to create reusable fragments of templates that can be included in multiple views. Think of them as modular building blocks for your web pages—write once, use everywhere!
In this tutorial, we'll explore:
- What template partials are and why they're useful
- How to implement partials in popular templating engines (EJS, Handlebars, and Pug)
- Best practices for organizing and structuring your partials
What Are Template Partials?
Template partials are reusable template fragments that can be included in other templates. They're particularly useful for components that appear on multiple pages, such as:
- Headers and footers
- Navigation menus
- Sidebar components
- Authentication forms
- Alert/notification systems
- Card layouts
By using partials, you can:
- Maintain consistency across your website
- Update components in one place
- Keep your templates clean and focused
- Improve developer collaboration
Setting Up Express with Templating Engines
Before we dive into partials, let's make sure we have a basic Express application set up with a templating engine.
const express = require('express');
const path = require('path');
const app = express();
// Set the view engine (choose one of these)
app.set('view engine', 'ejs'); // for EJS
// app.set('view engine', 'hbs'); // for Handlebars
// app.set('view engine', 'pug'); // for Pug
// Set views directory
app.set('views', path.join(__dirname, 'views'));
// Serve static files
app.use(express.static(path.join(__dirname, 'public')));
app.get('/', (req, res) => {
res.render('index', { title: 'Home Page' });
});
app.listen(3000, () => {
console.log('Server running on port 3000');
});
Now, let's see how to implement partials in different templating engines.
Implementing Partials in EJS
Setting Up EJS Partials
EJS (Embedded JavaScript) offers a straightforward approach to partials using the include
function.
First, create a folder structure like this:
views/
├── partials/
│ ├── header.ejs
│ ├── footer.ejs
│ └── navbar.ejs
├── index.ejs
├── about.ejs
└── contact.ejs
Creating Partials
Let's create some basic partials:
views/partials/header.ejs
:
<!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/style.css">
</head>
<body>
views/partials/navbar.ejs
:
<nav class="navbar">
<div class="logo">
<a href="/">My Website</a>
</div>
<ul class="nav-links">
<li><a href="/">Home</a></li>
<li><a href="/about">About</a></li>
<li><a href="/contact">Contact</a></li>
</ul>
</nav>
views/partials/footer.ejs
:
<footer>
<p>© <%= new Date().getFullYear() %> My Website. All rights reserved.</p>
</footer>
<script src="/js/main.js"></script>
</body>
</html>
Using Partials in Templates
Now, let's use these partials in our main view:
views/index.ejs
:
<%- include('partials/header') %>
<%- include('partials/navbar') %>
<main>
<h1>Welcome to My Website</h1>
<p>This is the home page of my awesome website.</p>
</main>
<%- include('partials/footer') %>
Notice the use of <%-
instead of <%=
for includes. This tells EJS to render the HTML without escaping it.
Passing Variables to Partials
You can pass variables to your partials as a second parameter to the include
function:
<%- include('partials/header', {title: 'Custom Page Title'}) %>
If you don't explicitly pass variables, partials can access variables from the parent template.
Implementing Partials in Handlebars
Setting Up Handlebars Partials
For Handlebars, you'll need to register your partials before using them. First, install required packages:
npm install express-handlebars
Then update your Express app:
const express = require('express');
const { engine } = require('express-handlebars');
const path = require('path');
const app = express();
// Setup Handlebars
app.engine('hbs', engine({
extname: '.hbs',
partialsDir: path.join(__dirname, 'views/partials')
}));
app.set('view engine', 'hbs');
app.set('views', path.join(__dirname, 'views'));
Creating Partials
Create your partials in the views/partials
directory:
views/partials/header.hbs
:
<!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/style.css">
</head>
<body>
views/partials/navbar.hbs
:
<nav class="navbar">
<div class="logo">
<a href="/">My Website</a>
</div>
<ul class="nav-links">
<li><a href="/">Home</a></li>
<li><a href="/about">About</a></li>
<li><a href="/contact">Contact</a></li>
</ul>
</nav>
views/partials/footer.hbs
:
<footer>
<p>© {{year}} My Website. All rights reserved.</p>
</footer>
<script src="/js/main.js"></script>
</body>
</html>
Using Partials in Templates
Now use these partials in your main template:
views/index.hbs
:
{{> header}}
{{> navbar}}
<main>
<h1>Welcome to My Website</h1>
<p>This is the home page of my awesome website.</p>
</main>
{{> footer}}
Passing Variables to Handlebars Partials
For dynamic year in the footer, update your route to include it:
app.get('/', (req, res) => {
res.render('index', {
title: 'Home Page',
year: new Date().getFullYear()
});
});
Implementing Partials in Pug
Setting Up Pug Partials
Pug (formerly Jade) has a different approach to partials using the include
and extends
keywords.
const express = require('express');
const app = express();
app.set('view engine', 'pug');
app.set('views', path.join(__dirname, 'views'));
Create a folder structure similar to the others:
views/
├── partials/
│ ├── header.pug
│ ├── footer.pug
│ └── navbar.pug
├── index.pug
├── about.pug
└── contact.pug
Creating Partials
views/partials/header.pug
:
doctype html
html(lang="en")
head
meta(charset="UTF-8")
meta(name="viewport", content="width=device-width, initial-scale=1.0")
title= title
link(rel="stylesheet", href="/css/style.css")
body
views/partials/navbar.pug
:
nav.navbar
.logo
a(href="/") My Website
ul.nav-links
li
a(href="/") Home
li
a(href="/about") About
li
a(href="/contact") Contact
views/partials/footer.pug
:
footer
p © #{new Date().getFullYear()} My Website. All rights reserved.
script(src="/js/main.js")
Using Partials in Templates
There are two main ways to use partials in Pug:
1. Using include
:
views/index.pug
:
include partials/header
include partials/navbar
main
h1 Welcome to My Website
p This is the home page of my awesome website.
include partials/footer
2. Using layout inheritance with extends
and block
:
First, create a layout file:
views/layout.pug
:
doctype html
html(lang="en")
head
meta(charset="UTF-8")
meta(name="viewport", content="width=device-width, initial-scale=1.0")
title= title
link(rel="stylesheet", href="/css/style.css")
body
include partials/navbar
block content
include partials/footer
Then your page simply extends the layout:
views/index.pug
:
extends layout
block content
main
h1 Welcome to My Website
p This is the home page of my awesome website.
This approach is often preferred as it gives more structure to your templates.
Real-World Application: Blog Template
Let's create a more comprehensive example of a blog site using partials. We'll use EJS for this example, but the concepts apply to any templating engine.
Project Structure
views/
├── partials/
│ ├── header.ejs
│ ├── footer.ejs
│ ├── navbar.ejs
│ ├── sidebar.ejs
│ └── post-card.ejs
├── index.ejs
├── post.ejs
└── about.ejs
Creating Advanced Partials
views/partials/post-card.ejs
(A reusable blog post preview):
<article class="post-card">
<div class="post-image">
<img src="<%= post.imageUrl %>" alt="<%= post.title %>">
</div>
<div class="post-content">
<h3><a href="/post/<%= post.id %>"><%= post.title %></a></h3>
<div class="post-meta">
<span class="date"><%= new Date(post.date).toLocaleDateString() %></span>
<span class="author">By <%= post.author %></span>
</div>
<p><%= post.excerpt %></p>
<a href="/post/<%= post.id %>" class="read-more">Read More</a>
</div>
</article>
views/partials/sidebar.ejs
:
<aside class="sidebar">
<div class="widget">
<h3>Recent Posts</h3>
<ul>
<% recentPosts.forEach(function(post) { %>
<li><a href="/post/<%= post.id %>"><%= post.title %></a></li>
<% }); %>
</ul>
</div>
<div class="widget">
<h3>Categories</h3>
<ul>
<% categories.forEach(function(category) { %>
<li><a href="/category/<%= category.slug %>"><%= category.name %></a></li>
<% }); %>
</ul>
</div>
</aside>
The Homepage Template
views/index.ejs
:
<%- include('partials/header', {title: 'My Blog Home'}) %>
<%- include('partials/navbar') %>
<div class="container">
<div class="main-content">
<h1>Latest Blog Posts</h1>
<section class="posts-grid">
<% posts.forEach(function(post) { %>
<%- include('partials/post-card', {post: post}) %>
<% }); %>
</section>
<div class="pagination">
<% if (currentPage > 1) { %>
<a href="/?page=<%= currentPage - 1 %>" class="btn">Previous</a>
<% } %>
<% if (hasNextPage) { %>
<a href="/?page=<%= currentPage + 1 %>" class="btn">Next</a>
<% } %>
</div>
</div>
<%- include('partials/sidebar', {
recentPosts: recentPosts,
categories: categories
}) %>
</div>
<%- include('partials/footer') %>
Express Route
app.get('/', (req, res) => {
const page = parseInt(req.query.page) || 1;
const postsPerPage = 6;
// Simulating database fetch (in a real app, this would come from a database)
const allPosts = [
{
id: 1,
title: 'Getting Started with Express',
author: 'Jane Doe',
date: '2023-03-15',
imageUrl: '/images/express.jpg',
excerpt: 'Learn how to build web applications with Express.js...'
},
// More posts...
];
const startIndex = (page - 1) * postsPerPage;
const selectedPosts = allPosts.slice(startIndex, startIndex + postsPerPage);
res.render('index', {
title: 'My Blog',
posts: selectedPosts,
currentPage: page,
hasNextPage: startIndex + postsPerPage < allPosts.length,
recentPosts: allPosts.slice(0, 5),
categories: [
{name: 'JavaScript', slug: 'javascript'},
{name: 'Node.js', slug: 'nodejs'},
{name: 'Express', slug: 'express'}
// More categories...
]
});
});
Best Practices for Working with Partials
-
Organized Directory Structure: Keep your partials in a dedicated directory (like
/partials
) for easy management. -
Naming Conventions: Use clear, consistent naming:
- Use nouns for component partials (header, footer, card)
- Consider prefixing with purpose (form-login, modal-signup)
-
Keep Partials Focused: Each partial should do one thing well - follow the Single Responsibility Principle.
-
Variable Scope: Be mindful of variable scopes in different template engines. Some engines automatically pass parent variables to partials, others require explicit passing.
-
Documentation: Add comments at the top of partial files explaining:
- What the partial does
- Required variables/parameters
- Example usage
-
Conditional Rendering: Make partials flexible with conditional rendering:
<!-- In header.ejs -->
<head>
<title><%= typeof title !== 'undefined' ? title : 'Default Title' %></title>
<% if (typeof metaDescription !== 'undefined') { %>
<meta name="description" content="<%= metaDescription %>">
<% } %>
</head>
- Avoid Nesting Too Deep: While you can include partials within partials, too much nesting can make your code hard to follow.
Common Challenges and Solutions
Challenge 1: Partials Not Finding Files
Problem: You get errors like "partial not found" or "cannot find module".
Solution: Double check paths. Remember that paths are relative to the views directory, not the file including the partial.
Challenge 2: Variables Not Available in Partials
Problem: Variables from parent templates aren't accessible in partials.
Solution: Explicitly pass the needed variables to the partial:
<%- include('partials/header', {title: pageTitle, user: currentUser}) %>
Challenge 3: Performance with Many Partials
Problem: Too many partials can impact rendering performance.
Solution:
- Only use partials for truly reusable components
- Consider caching strategies for your templates
- Use layout inheritance (extends/blocks) where appropriate
Summary
Template partials are a powerful way to keep your code DRY and maintain consistency across your Express application. They allow you to:
- Extract reusable components into separate files
- Maintain consistent elements like headers, footers, and navigation
- Create modular, maintainable templates
- Keep your main templates clean and focused
Each templating engine has its own approach to partials, but the core concept remains the same: write once, use everywhere. Whether you're using EJS, Handlebars, Pug, or another engine, mastering partials will significantly improve your development workflow and the quality of your Express applications.
Further Resources and Exercises
Resources
Exercises
-
Basic Implementation: Create a simple Express app with header, footer, and navigation partials using your preferred template engine.
-
Component Library: Build a UI component library using partials for buttons, cards, forms, and alerts.
-
Dynamic Navigation: Create a navigation partial that highlights the current page and shows/hides items based on user authentication status.
-
Multi-Layout System: Implement a system with multiple layouts (e.g., public site, dashboard, admin panel) using partials and template inheritance.
-
Advanced Blog: Extend the blog example from this tutorial to include comment sections, author profiles, and category pages - all using appropriate partials.
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)