EJS templates
Building HTML from strings inside a handler is awkward and dangerous. A template is an HTML file with placeholders where the server inserts data. EJS (Embedded JavaScript) is a simple template engine for Express: you write ordinary JavaScript inside ordinary HTML.
Installation and setup
npm install ejsIn src/app.js tell Express which template engine to use:
// src/app.js
app.set('view engine', 'ejs');Express looks for templates in the views/ folder in the project root, and the files have the .ejs extension.
The first template
Create the file views/posts/index.ejs:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title><%= title %></title>
</head>
<body>
<h1><%= title %></h1>
</body>
</html>The <%= title %> placeholder prints the value of the title variable.
Passing data
In the controller replace res.send() with res.render(). The first argument is the template path inside views/ without the extension, the second is an object with data:
// src/controllers/postsController.js
import { posts } from '../data/posts.js';
export function index(req, res) {
res.render('posts/index', { title: 'All posts', posts });
}Open /posts and you see a page with the heading "All posts". Every field of the object becomes a variable in the template.
Loops and conditions
Inside <% %> you write code that prints nothing — for example, a loop over the posts:
<h1><%= title %></h1>
<% if (posts.length === 0) { %>
<p>No posts yet.</p>
<% } %>
<ul>
<% for (const post of posts) { %>
<li><a href="/posts/<%= post.id %>"><%= post.title %></a></li>
<% } %>
</ul>Now /posts shows a list of links, each leading to the page of its post.
Kinds of tags
| Tag | What it does |
|---|---|
<%= value %> | Prints the value, escaping HTML |
<%- value %> | Prints the value as is, without escaping |
<% code %> | Runs code, prints nothing |
<%# comment %> | A comment, does not reach the HTML |
Data for every template
What every page needs is put into res.locals in middleware — these fields are visible in all templates without passing them to render():
// src/app.js
app.use((req, res, next) => {
res.locals.siteName = 'The Express blog';
next();
});Now any template can use <%= siteName %>.
Common mistake
Do not print visitor data with <%-. If a post title contains a string with a script, <%- inserts it into the page as code, and the script runs for every reader. This is called an XSS attack. Use <%= for any data: it turns < and > into safe characters. Keep <%- for inserting other templates — they are the topic of the next lesson.