Use <template> to Restore DOM State

by Julian Rubisch

Pain Point

Good

<!-- index.html -->
<div data-controller="modal">
  <template data-modal-target="template">
    <div>
      <a href="#" data-action="modal#show">Click Me</a>
      <div class="modal invisible" data-modal-target="modal">
        <h1>A Modal</h1>
        <a href="#" data-action="modal#hide">Hide Me</a>
      </div>
    </div>
  </template>
</div>

// modal_controller.js
import { Controller } from "@hotwired/stimulus";

export default class extends Controller {
  static targets = ["template", "modal"];

  connect() {
    this.element.insertAdjacentHTML("beforeend", this.templateTarget.innerHTML);
  }

  show(e) {
    e.preventDefault();

    // this is a stand-in for an external show method, e.g. in Bootstrap or SemanticUI
    this.modalTarget.classList.remove("invisible");
    this.modalTarget.classList.add("visible");
  }

  hide(e) {
    e.preventDefault();

    // this is a stand-in for an external hide method that will
    // yank the modal HTML off your page
    this.element.removeChild(this.element.lastElementChild);

    this.element.insertAdjacentHTML("beforeend", this.templateTarget.innerHTML);
  }
}


Rationale

In some cases, it can be necessary to reset your DOM to a known state before leaving the page, or after triggering some action. One use case might be when dealing with external UI libraries like SemanticUI or Bootstrap that will yank away some HTML after, for example, closing a modal.

Furthermore this can be useful when using Turbo, because it will cache the current state before navigating away and show it as a preview when doing a restoration visit.

Contraindications

Certainly there are easier ways to restore markup when manipulating the DOM, especially when you’re dealing only with single elements on which you toggle CSS classes. Whenever you need to replace larger portions of HTML, this can be a viable option, though.

References