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
const express = require('express');const app = express()
// Set the view engineapp.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});
<!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
<% 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
const express = require('express');const app = express()
// Set the view engineapp.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" }, ] });});
<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>
<footer> <p>© 2025 Nadith's Site</p></footer>
<!DOCTYPE html><html><head> <title>Home</title></head><body> <% include partials/header %>
<h2>Welcome to the Home Page</h2>
<% include partials/footer %></body></html>
π‘ EJS
uses the <% include path %>
syntax to import partials.
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:
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>
<h1>Home</h1><p>This is the home page</p>
π― 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
Concept | Purpose |
---|---|
Partials | Reusable HTML blocks (like header.ejs ) |
Layouts | Master page template (like layout.ejs ) |
express-ejs-layouts | Allows EJS to support layout injection |
<%- body %> | Placeholder where page content gets inserted |