2023-05-18 - Stimulus JS

main topics


During this lecture I noticed a knowledge gap about webpack. Solved this by watching this origamid lecture


A modest JavaScript framework for the HTML you already have.

So, the "3 steps JS" thing that I memorized can now be simplified.

The "3 steps JS":

  1. select some elements
  2. define a function (behavior)
  3. define which event, happening in wich element, should trigger which function (sometimes changing other elements)

With Stimulus our JavaScript code will be focused on the behavior. The elements to be selected and the events we want to listen are explicitly mentioned in the HTML, specifically in the elements' data-attributes .

While reading The Origin of Stimulus I noticed that "the focus of Stimulus is on manipulating, not creating, DOM elements."

Unlike other front-end frameworks, Stimulus is designed to enhance static or server-rendered HTML—the “HTML you already have”—by connecting JavaScript objects to elements on the page using simple annotations.

(...) Stimulus’s use of data attributes helps separate content from behavior in the same way CSS separates content from presentation.

Key Concepts

mnemonic: CAT 😺


At its core, Stimulus’s purpose is to automatically connect DOM elements to JavaScript objects. Those objects are called controllers.

Let’s create our first controller by extending the framework’s built-in Controller class. Create a new file named src/controllers/hello_controller.js:

// src/controllers/hello_controller.js
import { Controller } from "@hotwired/stimulus"

export default class extends Controller {}

In order to connect to this 👆 controller, we need to go to our HTML and mark an element there as data-controller. Like this:

<div data-controller="hello">
  <input type="text">

NOTE: inside the Controller class, the this.element has the element where the data-controller attribute is defined.

NOTE 2: you can do this this.element.querySelector(cssSelector).


An action assign a behavior to an element. Here's an example:

To connect our action method to the button’s click event, open public/index.html and add a data-action attribute to the button:

<div data-controller="hello">
  <input type="text">
  <button data-action="click->hello#greet">Greet</button>

Action Descriptors Explained

The data-action value click->hello#greet is called an action descriptor. This particular descriptor says:

Remember: inside the Controller class, the this.element has the element where the data-controller attribute is defined.


A Target is an element on which we want to act.

In the HTML it's like this:

<div data-controller="hello">

  // here 👇
  <input data-hello-target="name" type="text">

  <button data-action="click->hello#greet">Greet</button>

And in the *_controller.js we can grab it like this:

import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  // the target name goes as an element of `targets`
  static targets = [ "name" ]
  greet() {
    // and it's accessible by `this.${targetName}Target`
    const element = this.nameTarget
    const name = element.value
    console.log(`Hello, ${name}!`)


Installation guide (assumes use of webpack).

npm install @hotwired/stimulus
npm install @hotwired/stimulus-webpack-helpers

Put this in index.js (or whichever file is linked in your html):

import { Application } from "@hotwired/stimulus"
import { definitionsFromContext } from "@hotwired/stimulus-webpack-helpers"

window.Stimulus = Application.start()
const context = require.context("./controllers", true, /\.js$/)

Now you can create #Controllers.