Layout Patterns
Partials handle internal components, but they don’t solve the problem of repeated structural boilerplate (like <html>, <head>, and <body> tags) in every file. To achieve true maintainability, we use a “Layout” pattern—a master template that wraps around your individual views.
The Layout Module
Section titled “The Layout Module”Standard EJS does not support layouts out of the box. We must install a middleware package to enable this functionality.
Installation
Section titled “Installation”npm install express-ejs-layoutsConfiguration
Section titled “Configuration”We must register the middleware before our route definitions and configure the default layout file.
File: app.js
const expressLayouts = require("express-ejs-layouts");
// Middleware: Enable the layout engineapp.use(expressLayouts);
// Configuration: Set the default layout file// This assumes a file exists at /views/layouts/full-width.ejsapp.set("layout", "./layouts/full-width");The Master Layout File
Section titled “The Master Layout File”A layout file is a standard EJS template with one special variable: body. When express-ejs-layouts processes a request, it renders your specific view (e.g., users.ejs) first, stores the result in a string, and then injects that string into the layout’s <%- body %> tag.
File: views/layouts/full-width.ejs
<!DOCTYPE html><html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title><%= title %></title> <link rel="stylesheet" href="/styles/main.css" /> </head> <body> <!-- Persistent Navigation --> <%- include('../partials/header.ejs') %>
<!-- Injection Point: The specific view content renders here --> <main><%- body %></main>
<!-- Persistent Footer --> <%- include('../partials/footer.ejs') %> </body></html>Simplified Views
Section titled “Simplified Views”With the layout handling the frame, your individual view files become much cleaner. They only need to contain the content relevant to that specific route.
File: views/things.ejs
<!-- No <html>, <head>, or <body> tags needed here --><article class="card"> <header> <h2>Inventory Log</h2> <h3>[ All the Things ]</h3> </header> <section> <p class="bio"> "This area is designated for Thing containment. Do not feed the objects." </p> <p>The dynamic list of Things is rendered here.</p> <p> Currently, the data is hardcoded in the router. In a real application, the data would be retrieved from a database. </p> <h4>// Status_Report</h4> <ul> <% things.forEach(thing => { %> <li> <a href="/things/<%= thing.id %>" style="color: inherit; text-decoration: none; display: block; width: 100%;" > <%= thing.name %> <% if (!thing.active) { %> (Inactive) <% } %> </a> </li> <% }) %> </ul> </section></article>Extra Bits & Bytes
Section titled “Extra Bits & Bytes”EJS Layouts - GitHub Repo