Mastering EJS: Building Dynamic Web Applications with Embedded JavaScript

A Comprehensive Guide to Setup, Syntax, and Building an Example Application with EJS

Mastering EJS: Building Dynamic Web Applications with Embedded JavaScript

Introduction

Dynamic and interactive web applications have become essential in modern development. EJS (Embedded JavaScript) is a powerful templating language that bridges the gap between server-side data processing and rendering dynamic HTML. Its simplicity, flexibility, and seamless integration with Node.js make it a go-to tool for building server-rendered applications.

This guide covers everything you need to know about EJS, including its features, syntax, setup, and implementation, along with a practical example application.


What is EJS?

EJS (Embedded JavaScript) is a templating engine that enables developers to:

  • Embed JavaScript logic directly within HTML templates.

  • Dynamically render server-side data on the client.

  • Create modular, reusable components for streamlined development.

EJS is lightweight, easy to learn, and ideal for applications requiring server-side rendering with Node.js.


Key Features of EJS

  1. Dynamic HTML Rendering: Generate dynamic web pages with ease by embedding JavaScript within your templates.

  2. Simple Syntax: Use intuitive tags like <%= %> to output data or <% %> for inline JavaScript logic.

  3. Reusable Templates: Modularize your views using includes and layouts for consistent design.

  4. Seamless Integration: Works out-of-the-box with Node.js frameworks like Express.

  5. Performance: Minimal overhead ensures fast rendering of dynamic content.


How to Set Up EJS

Before diving into examples, let’s set up EJS in a Node.js project.

Prerequisites

Ensure you have Node.js and npm installed. If not, download and install them from Node.js.

Installation

Initialize a new Node.js project and install EJS:

npm init -y
npm install ejs

Configuring EJS with Express

Step 1: Setting Up Express

Create a basic Express server and configure EJS as the view engine:

import express from "express";
const app = express();

// Set EJS as the view engine
app.set("view engine", "ejs");

// Define the views directory
app.set("views", "views");

// Sample route
app.get("/", (req, res) => {
  res.render("index", { title: "Welcome to EJS!", message: "Hello, World!" });
});

// Start the server
app.listen(3000, () => {
  console.log("Server running on http://localhost:3000");
});

This setup allows Express to locate .ejs files in the views folder and render them dynamically.

Folder Structure

Your project should follow this structure:

/project
  /views
    index.ejs
  server.js
  package.json

EJS Syntax and Examples

EJS offers a simple and intuitive syntax for embedding logic and data into HTML templates.

1. Outputting Data

  • Escaped Output: Safely outputs HTML-escaped data.

      <%= data %>
    

    Example:

      <h1>Welcome, <%= username %>!</h1>
    

    Output: Welcome, John!

  • Unescaped Output: Outputs raw HTML (use cautiously to avoid XSS vulnerabilities).

      <%- htmlContent %>
    

2. JavaScript Logic

EJS allows inline JavaScript logic:

  • Conditionals:

      <% if (isLoggedIn) { %>
        <p>You are logged in.</p>
      <% } else { %>
        <p>Please log in.</p>
      <% } %>
    
  • Loops:

      <ul>
        <% items.forEach(item => { %>
          <li><%= item %></li>
        <% }); %>
      </ul>
    

3. Including Templates

Reuse components by including partials:

<%- include("partials/header") %>
<h1>Main Content</h1>
<%- include("partials/footer") %>

Building an Example Application

Let’s create a simple secrets-sharing app with the given code snippets.

Application Overview

  • Functionality:

    • Users can register, log in, and view a "secret" page.

    • Templates dynamically render data and share common layouts.

  • Folder Structure:

      /project
        /views
          /partials
            header.ejs
            footer.ejs
          home.ejs
          login.ejs
          register.ejs
          secrets.ejs
        server.js
    

Code Implementation

1. Home Page Template (home.ejs)

<%- include('partials/header') %>
<div class="jumbotron centered">
  <div class="container">
    <h1 class="display-3">Secrets</h1>
    <p class="lead">Don't keep your secrets, share them anonymously!</p>
    <a class="btn btn-light btn-lg" href="/register">Register</a>
    <a class="btn btn-dark btn-lg" href="/login">Login</a>
  </div>
</div>
<%- include('partials/footer') %>

2. Login Page (login.ejs)

<%- include('partials/header') %>
<div class="container mt-5">
  <h1>Login</h1>
  <form action="/login" method="POST">
    <div class="form-group">
      <label for="email">Email</label>
      <input type="email" class="form-control" name="username">
    </div>
    <div class="form-group">
      <label for="password">Password</label>
      <input type="password" class="form-control" name="password">
    </div>
    <button type="submit" class="btn btn-dark">Login</button>
  </form>
</div>
<%- include('partials/footer') %>

3. Register Page (register.ejs)

<%- include('partials/header') %>
<div class="container mt-5">
  <h1>Register</h1>
  <form action="/register" method="POST">
    <div class="form-group">
      <label for="email">Email</label>
      <input type="email" class="form-control" name="username">
    </div>
    <div class="form-group">
      <label for="password">Password</label>
      <input type="password" class="form-control" name="password">
    </div>
    <button type="submit" class="btn btn-dark">Register</button>
  </form>
</div>
<%- include('partials/footer') %>

4. Secrets Page (secrets.ejs)

<%- include('partials/header') %>
<div class="jumbotron text-center">
  <h1>You've Discovered My Secret!</h1>
  <p class="secret-text">This is a hidden message.</p>
  <a class="btn btn-light btn-lg" href="/logout">Log Out</a>
</div>
<%- include('partials/footer') %>
  • header.ejs:

      <!DOCTYPE html>
      <html lang="en">
      <head>
        <meta charset="UTF-8">
        <title>Secrets</title>
        <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css">
      </head>
      <body>
    
  • footer.ejs:

      </body>
      </html>
    

Server Logic

import express from "express";
const app = express();

app.set("view engine", "ejs");
app.use(express.static("public"));
app.use(express.urlencoded({ extended: true }));

// Routes
app.get("/", (req, res) => res.render("home"));
app.get("/login", (req, res) => res.render("login"));
app.get("/register", (req, res) => res.render("register"));
app.get("/secrets", (req, res) => res.render("secrets"));

// Start Server
app.listen(3000, () => {
  console.log("Server running on http://localhost:3000");
});

Conclusion

EJS empowers developers to build robust, dynamic web applications using familiar JavaScript syntax. By integrating seamlessly with Node.js and Express, EJS simplifies server-side rendering while promoting code reuse and maintainability.

Try implementing the example application to explore the versatility of EJS in action!