Skip to content

3. EJS

1. Introduction

EJS (Embedded JavaScript Templating) is a simple templating language that lets you generate HTML markup with plain JavaScript.

Features

  • Use plain JavaScript: Unlike pug, ejs uses JS!
  • Fast development time: Don’t waste time learning complex new syntax or preprocessing data for proper rendering.
  • Simple syntax: Just write JavaScript that emits the HTML you want, and get the job done!
  • Speedy execution: We all know how fast V8 and the other JavaScript runtimes have gotten. EJS caches the intermediate JS functions for fast execution.
  • Easy debugging: It’s easy to debug EJS errors: your errors are plain JavaScript exceptions, with template line-numbers included.
  • Active development: EJS has a large community of active users, and the library is under active development. We’re happy to answer your questions or give you help.

2. Example

Create a file hello.ejs and place it in .\views folder

πŸ—‚ Folder structure:

  • DirectorytestNodeProject/
    • Directoryviews/
      • hello.ejs
    • server.js
    • package.json

In server.js set the view engine to ejs

server.js
const express = require('express');
const app = express()
// Set the view engine
app.set( 'view engine', 'ejs' );
// Set handler for the root '/'
app.get('/', (req, res) => {
res.render('hello', {theTitle: 'This is the Title'});
// this will look for the file 'hello.ejs' in './views' folder
// second parameter to render(...) method is optional
});
hello.ejs
<!DOCTYPE html>
<html lang="en">
<head>
<title>Hello World! <%= locals.theTitle || "Default Value" %></title>
</head>
<body>
<h1>Hello World!</h1>
<div class="remark">
<p>EJS rocks!!</p>
</div>
</body>
</html>

It is important to use locals.theTitle instead of theTitle in the .ejs file above since the page will report an error if the parameter is not defined during the call to res.render(...) method. In contrast, locals dictionary will always be defined internally when called res.render(...) method. if a parameter (i.e. theTitle) is not defined, locals.theTitle will simply return nothing.

Rendered output, when http://localhost:3000/ is accessed

<!DOCTYPE html>
<html lang="en">
<head>
<title>Hello World! This is the Title</title>
</head>
<body>
Hello World This is the Title
</body>
</html>

3. Control Flow Statements

Similar to JavaScript, EJS provides a syntax for using conditional logic within your HTML templates. Following demonstrate practical examples of using conditional statements with the EJS template

3.1 Conditional Statements

Below is an example of using a if conditional statement in ejs

./views/index.ejs
<% if(true){ %>
<h1>foo</h1>
<% } else { %>
<h1>bar</h1>
<% } %>
{% endcapture %}

3.2 Looping Statements

Below is an example of using a for loop statement in ejs

server.js
const express = require('express');
const app = express()
// Set the view engine
app.set( 'view engine', 'ejs' );
// Set handler for the root '/'
app.get('/', (req, res) => {
res.render('index', { data: [
{ id: 1, name: "bob" },
{ id: 2, name: "john" },
{ id: 3, name: "jake" },
] });
});
./views/index.ejs
<table>
<% for(var i=0; i < data.length; i++) { %>
<tr>
<td><%= data[i].id %></td>
<td><%= data[i].name %></td>
</tr>
<% } %>
</table>

Rendered output, when http://localhost:3000/ is accessed

<table>
<tbody>
<tr>
<td>1</td>
<td>bob</td>
</tr>
<tr>
<td>2</td>
<td>john</td>
</tr>
<tr>
<td>3</td>
<td>jake</td>
</tr>
</tbody>
</table>

4. Partials and Layout Systems

Partials are reusable view components β€” like headers, footers, navbars β€” that you can include in multiple EJS pages.

Think of them like β€œHTML includes.”

4.1 βœ… Creating and Using Partials

πŸ“ Folder structure

  • Directoryviews/
    • Directorypartials/
      • header.ejs
      • footer.ejs
    • index.ejs
    • about.ejs
<header>
<h1>My Website</h1>
<nav>
<a href="/">Home</a> |
<a href="/about">About</a>
</nav>
</header>

4.2 πŸ“¦ What Is express-ejs-layouts?

By default, EJS doesn’t support layouts like some other engines (e.g., Pug or Handlebars).
The express-ejs-layouts package helps you:

  • Define a master layout
  • Inject your content (<%- body %>) into it from different views

πŸ”§ Setup:

Terminal window
npm install express-ejs-layouts
const express = require('express');
const app = express();
const expressLayouts = require('express-ejs-layouts');
app.set('view engine', 'ejs');
app.use(expressLayouts); // ⬅️ Add this

πŸ—‚ Folder structure:

  • Directoryviews/
    • layout.ejs
    • index.ejs
    • about.ejs
<!DOCTYPE html>
<html>
<head>
<title><%= title %></title>
</head>
<body>
<%- body %> <!-- All page content will go here -->
</body>
</html>

🎯 In your route:

app.get('/', (req, res) => {
res.render('index', { title: 'Home Page' });
});

The rendered result will be:

  • layout.ejs + index.ejs content inside <%- body %>

4.3 βœ… Summary

ConceptPurpose
PartialsReusable HTML blocks (like header.ejs)
LayoutsMaster page template (like layout.ejs)
express-ejs-layoutsAllows EJS to support layout injection
<%- body %>Placeholder where page content gets inserted