Skip to content

Template partials

The problem

Many pages in a website might share the same content. For example, our views might look like this (the repeated content has been highlighted):

html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Bleeter | <%= title %></title>
  </head>

  <body>
    <h1>Welcome to Bleeter</h1>
    <h2>Follow the herd</h2>
  </body>
</html>
html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Bleeter | <%= title %></title>
  </head>

  <body>
    <h1>Bleets</h1>
    <ol>
      <% for (let bleet of bleets) { %>
      <!-- use bleet -->
      <li>
        <%= bleet.content.slice(0, 10) + '...' %>
        <a href="<%= `/bleets/${bleet.id}` %>">Read more</a>
      </li>
      <% } %>
    </ol>
  </body>
</html>
html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Bleeter | <%= title %></title>
  </head>

  <body>
    <h1>A bleet</h1>
    <p><%= bleet.content %></p>
    <p><%= bleet.createdAt %></p>
  </body>
</html>

This is a problem, because if we need to make a change to the shared parts of each view, we need to update each view individually, which is extra work and an opportunity for mistakes.

Creating partials

We can create partial templates and use them in our views.

The directory structure might look like this:

txt
views/
├── bleet.ejs
├── bleets.ejs
├── index.ejs
└── partials
    ├── footer.ejs
    └── header.ejs

We will put the repeated HTML into the partial templates.

html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Bleeter | <%= title %></title>
  </head>

  <body>
html
  </body>
</html>

Using partials

To use the partial templates in our views, we use the EJS include function.

html
<%- include('partials/header') %>

<h1>Welcome to Bleeter</h1>
<h2>Follow the herd</h2>

<%- include('partials/footer') %>
html
<%- include('partials/header') %>

<h1>Bleets</h1>
<ol>
  <% for (let bleet of bleets) { %>
  <!-- use bleet -->
  <li>
    <%= bleet.content.slice(0, 10) + '...' %>
    <a href="<%= `/bleets/${bleet.id}` %>">Read more</a>
  </li>
  <% } %>
</ol>

<%- include('partials/footer') %>
html
<%- include('partials/header') %>

<h1>A bleet</h1>
<p><%= bleet.content %></p>
<p><%= bleet.createdAt %></p>

<%- include('partials/footer') %>

DANGER

When rendering untrusted content such as user input (including input stored in the database), always use <%= %> and not <%- %>. The ensures that the HTML content is escaped and prevents XSS attacks.

INFO

Partials have access to the data of their parent! So, for example, the title which is passed to the index.ejs template is available in the header.ejs partial.