Skip to content

Importing HTML and CSS

The previous examples works well but maybe you noticed that all the CSS was loaded into the global scope. The classname amazing-button would affect all elements of the page.

Furthermore we want to show how to use EJS features in imported HTML files.

To make the CSS to affect only the template we have first to create a CSS with the extension .module.css. This enables the compilation of the CSS into a CSS Module. Now you can use local class names.

For this we replace the topmost classname .amazing-button with :local(.amazing-button). This makes this class later available over module properties and the class name will be replaced by a random value.

src/amazing-button.module.css

:local(.amazing-button) { /* (1)! */
  --my-color: #f30000;

  text-align: center;

  & .card-header {
    color: var(--my-color);
    background-image: url("images/favicon.png");
    background-size: contain;
    background-repeat: no-repeat;
    background-position-x: left;
  }
}
  1. This will replace the classname .amazing-button with a local unique id

To enable the use of EJS-Variables in the HTML structure you have to create a file with the extension .ejs.html:

src/amazing-button.ejs.html

<div class="card h-100"> <!-- (1)! -->
  <div class="card-header">
    <%= locals.myTitleVariable %>  <!-- (2)! -->
  </div>
  <div class="card-body">
    <h5 class="card-title">Click on the button to see the miracle</h5>
    <p class="card-text">
      <button class="btn btn-secondary">Press Me</button>
    </p>
    <div class="result border border-primary mb-2">No Result</div>
    <img src="<%- require('./images/favicon.png') %>" /> <!-- (3)! -->
  </div>
</div>
  1. The topmost div do not contain the class amazing-button as we will insert it later dynamically
  2. We replaced the title "Amazing Button" with an EJS variable
  3. In EJS Templates you have to change links to assets like images into a require statement! They must start with ./.

Info

By the way: You can use here also include statements with <%- include another-file.html %>. But you have to pay attention that changes in included files will not be detected by the webpack devserver and the automatic rebuild will not include the new content.

Now we can write our new class:

src/amazing-button-variable.js

import $ from "jquery";
import htmlTemplate from "./amazing-button.ejs.html";
import styles from "./amazing-button.module.css"; // (1)!
export default class {
  #maximumNumber = 9;
  #button;
  get maximumNumber() {
    return this.#maximumNumber;
  }
  set maximumNumber(value) {
    this.#maximumNumber = value;
    this.#button.html(`Show number from 1 to ${this.#maximumNumber}`);
  }
  constructor(element) {
    console.debug("Starting Variable Button");
    $(element).html(htmlTemplate({ myTitleVariable: "Amazing Variable Button" })); // (2)!
    $(element).addClass(styles["amazing-button"]); // (3)!
    this.#button = $(element)
      .find("button")
      .html(`Show number from 1 to ${this.#maximumNumber}`)
      .on("click", () => {
        this.resultDiv.html(Math.floor(Math.random() * this.#maximumNumber));
      });
    this.resultDiv = $(element).find("div.result");
  }
}
  1. Import the stylesheet now as module instead of simple import "filename.css"
  2. The variable htmlTemplate is now a function which can be called to get the final text
  3. This imprted CSS module offers all class names in the statement :local() as properties

You have to change the import statements and the way on how the resulting HTML will be added to the element.

We import the stylesheet now as module called styles. This module offers all class names in the statement :local() as properties. In our case we can access the class name amazing-button with styles["amazing-button"]. This will return the local class name replacement value which we can add to our topmost div.

The HTML structure will also imported as module. The variable htmlTemplate do not contain anymore just the text of the file. It is a function which can be called to get the final text. As argument you can provide an object. All properties of the object are accessible in the EJS template as properties of the object locals.

Let's add another container in which we will start the new class:

src/index.js

import createTestContainer from "./create-test-container";

import { default as MyVanillaApp } from "./amazing-button-vanilla";
import { default as MyPackagesApp } from "./amazing-button-packages";
import { default as MyImportApp } from "./amazing-button-import";
import { default as MySvgApp } from "./amazing-button-svg";
import { default as MyDynamicApp } from "./amazing-button-dynamic";
import { default as MyVariableApp } from "./amazing-button-variable";
import { default as MyVueApp } from "./amazing-button-vue";

import "./style.css";

createTestContainer("Testing Vanilla JS", "test-container-vanilla");
let myVanillaInstance = new MyVanillaApp(
  document.getElementById("test-container-vanilla")
);
myVanillaInstance.maximumNumber = 99;

createTestContainer("Testing Packages", "test-container-packages");
let myPackagesInstance = new MyPackagesApp(
  document.getElementById("test-container-packages")
);
myPackagesInstance.maximumNumber = 49;

createTestContainer("Testing Import HTML/CSS/Assets", "test-container-import");
let myImportInstance = new MyImportApp(
  document.getElementById("test-container-import")
);
myImportInstance.maximumNumber = 79;

createTestContainer("Testing Import SVG", "test-container-svg");
new MySvgApp(document.getElementById("test-container-svg"));

createTestContainer("Testing Dynamic Imports", "test-container-dynamic");
let myDynamicInstance = new MyDynamicApp(
  document.getElementById("test-container-dynamic")
);
myDynamicInstance.maximumNumber = 55;

createTestContainer("Testing CSS/EJS Variables", "test-container-variable");
let myVariableInstance = new MyVariableApp(
  document.getElementById("test-container-variable")
);
myVariableInstance.maximumNumber = 45;

With npm start you should see the running example in your browser. If you inspect the page you will see an unique class name at the point where earlier amazing-button was noted.