Hello Stimulus JS

For the 2nd day in the Rails 7 week I present my version of: Stimulus JS Basics. When what you’re building is Rails with light interactions, marketing pages, landing pages, dashboard apps on Rails 7, Stimulus JS is exactly what you want. It gets out of your way just the right amount, making the easy easy and the hard possible.

This introduction is a brief alternative to the very good Stimulus Handbook, which covers several topics not covered here in-depth.

This post offers a brief introduction and then I will expound upon my thoughts (rant) on the evolution of Rails and Stimulus vs. React

To get a hands-on dive-in lesson where you will build something with Stimulus right away, try the Rails 7: Stimulus JS Basics with ImportMap-Rails instead.

Stimulus calls itself a “modest” framework and in doing so it tries to separate itself from the implementation-heavy likes of React, Vue, and Ember, and others. In particular, Stimulus is heavy on data-in-the-DOM, or “DOM decoration.” That means instead of taking control of the view away from HTML like React (because our application logic lives in a managed state of a big JS app), we’re going to leverage HTML for what it is good at: Structured data.

Stimulus has one core concept: The Stimulus Controller. Unlike Rails controllers, these object exist in a formal sense more like behaviors. The primary difference between a Stimulus controller and a Rails controller is that a Rails controller has only one instance within the context of a web request. A Stimulus controller, on the other hand, is more like a lightweight Javascript decorator or behavior attached to a part of your page (DOM element).

You may choose to decorate one part of your HTML with a Stimulus controller, or you can use the same controller in more than one place and it will create two instances.

You will decorate your page using the data-controller attribute, and then pass the controller name with hyphens (not underscores) between the words of any multi-word controller.

Meet Stimulus JS

Your Rails app now comes with a app/javascript/controllers where your Stimulus controllers will live.

Stimulus JS new folder structure

Take a look at app/javascript/controllers/application.js now

import { Application } from "@hotwired/stimulus"

const application = Application.start()

// Configure Stimulus development experience
application.debug = false
window.Stimulus = application

export { application }

Now take a look at the default hello_controller.js, which is provided as an example only. Add the line shown in orange.

import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  connect() {
    console.log("Stimulus connected the Hello controller"); 
    this.element.textContent = "Hello World!"

The next thing to look at is app/javascript/controllers/index.js

// Import and register all your controllers from the importmap under controllers/*

import { application } from "controllers/application"

// Eager load all controllers defined in the import map under controllers/**/*_controller
import { eagerLoadControllersFrom } from "@hotwired/stimulus-loading"
eagerLoadControllersFrom("controllers", application)

// Lazy load controllers as they appear in the DOM (remember not to preload controllers in import map!)
// import { lazyLoadControllersFrom } from "@hotwired/stimulus-loading"
// lazyLoadControllersFrom("controllers", application)

Here, we are automatically eager loading every file in the javascript/controllers folder that ends with the text _controller. Make sure that all your file names end with _controller.js

As well, because of ES Module default exports, note that every controller is exported as the name of the file itself, even though you don’t actually specify the object with an explicit name. When you have a two word controller name (or more), your want to use underscores in the file name and dashes (hyphens) when decorating. In this example, the controller is only the word hello. Be sure to see the Rails 7: Stimulus JS Basics with ImportMap-Rails example for a demonstration of a two-word controller name.

Wire Stimulus JS Up

Add to any page:

<div data-controller="hello"></div>

When you load your Rails app (rails s), examine your web console and confirm you see the message we added as console.log above. If you do, you have Stimulus wired up correctly.

You’re now ready to learn about defining targets, actions, and values.

The Stimulus JS Building Blocks

Let’s talk about a few building blocks. Consider this basic Stimulus controller and its corresponding view:

Stimulus JS Basic Example

Underscore vs. Dash Syntax vs. camelCase

(For two-or-more-word Controller Names)

• Although the JS objects become camelCase in Javascript, the camelCase naming is all but hidden from you the developer, except for the case of defining your targets, when you will to be sure to use camelCase in the Stimulus controller.

• When naming the file use underscores (e.g. the_chooser.js)

• In the view, you will always use dash syntax
When defining methods to invoke in actions it is common to use camelCase in JS, which can be confusing.
Both the

Stimulus JS filename syntax

The .element Attribute

The elements attribute gives you direct access to the HTML element that the Stimulus is wrapping.


connect the controller to DOM elements

Example with camelCase target (two-word) target names. Note that in the controller, you should camelCase your target names.


import { Controller } from "@hotwired/stimulus"

// Connects to data-controller="date-spanner"
export default class extends Controller {
  static targets = ["startDate", "endEnd", "resultsDisplay"]

This example is from the companion lesson to this blog post, Rails 7: Stimulus JS Basics with ImportMap-Rails which is more of a dive-in tutorial that will introduce you to the same Stimulus concepts.


connect the controller to DOM events

Stimulus JS Filenames are in Underscore but data attributes use dashes

Stimulus JS Action Syntax


read & write the data attributes of controller’s element

How it Fits With Rails

Remember, Stimulus is a DOM-friendly paradigm so you can rely on data attributes. As well, remember that you can define plain old HTML form elements, wrap them in Stimulus controllers, and then have the Stimulus controllers manipulate the form elements. You can insert hidden fields, remove hidden fields, or add or remove elements from your form.

This pattern works great, for example, for an in-page manipulation that is to happen before a form submission (now, with Rails 7 Turbo, a Turbo form submission.)

So essentially, keep your data in your DOM! When you want to submit forms, submit forms and let Turbo do its magic. For everything else, there’s Stimulus.

Jason’s Take

Stimulus demonstrates that most web app don’t really need heavy JS paradigms. While the allure of React is sexy to a certain sect of Silicon Valley, it hasn’t produced the level of successes for new ventures that Rails has.

Also, by not having benefitted from the 17 years of conceptual compression, the Node ecosystem has somewhat spiraled out of control with a plethora of options. Many good ones, no doubt. But they say road to hell is paved with good intentions.

What is so promising about Stimulus JS and Rails 7 is not that it is somehow more advanced Javascript— quite the opposite.

A keen observer might look at the web apps we are building today in 2022 and think, “How are these apps different than the apps of 2012?”

In truth, they aren’t actually that different.

Sure, our browsers can do WebRTC now (video chatting), and HTTP2 has made things faster, and we may have a few more features in the web browser (like HTML5 native date pickers).

But fundamentally, from the user’s perspective, very little has actually changed in the last 10 years.

From the programmer’s perspective— what a time to be alive! (to quote DHH). The last 10 years saw the rise of Github and Shopify (both two of Rails’ biggest success stories), a consolidation of Big Tech, major shifts in the understanding of Javascript (and now Typescript), nay, even programming itself— in some ways.

From a backend vs frontend perspective what has happened over the last 10 years makes total sense to me: Rails and Java, the primary server-based backend champions, are highly successful at simply being object oriented.

Writing a UI with objects is a disorienting and dizzying experience. That’s because fundamentally, UI and UX follows rules that are user centric and not business centric.

So when the advent of modern product development came about in the aughts (2000s), it made sense that the first attempts by programmers were to try to build UIs using objects.

What does this all have to do with Stimulus?

Nothing really, but it demonstrates how lost we are as an industry. Writing a large UI in an FP (React) based paradigm will cost you a lot in state management. Most people don’t need it.

So Stimulus may just the bridge we need. Its philosophy: The browser is just fine, we’re good, we can do what we need with just JS and HTML decoration.

Would I build a frontend data-heavy application with Stimulus? Probably not.

What most people don’t realize is that the web is no longer a place where people have high expectations.

Will React — or any other new JS paradigm’s promise of newness — produce a better result? A more profitable one? A result that is better for the user, the human, the planet? A result that is better for the business?

Nobody cares if your app was written using functions or objects.

Successful websites are the ones which load very fast, don’t have bugs, have seamless user interactions, clean UX, provide something new while also giving the feeling of old. (What Derek Thompson calls in his book Hit Makers, the “MAYA principle”— most advanced yet acceptable.)

That’s the stuff of great software. In order to make the above happen, you need great automated testing and a solid deployment pipeline (not to mention highly competent people who know what they are doing).

Can you build all of that in the Node ecosystem? Of course you can, it just costs a lot more and there’s very little industry-wide agreement about quality standards.

Unlike mobile development, where the new phones seem to be able to do things we didn’t even dream of in the past, the web browsers just aren’t functionally evolving very much any more.

You could put all the work in the world into building an efficient state-managed system in React but it wouldn’t make a difference: Your website will probably just load slowly (which as of 2022 will start hurting your Google rankings even more than it used to in the past) and likely be difficult to keep consistently tested.

Most web apps of the future will be light interactions, dashboard apps, marketing pages, landing pages, video streaming portals, etc. In these cases, Stimulus is just what is called for, no more no less.

Leave a Reply

Your email address will not be published. Required fields are marked *

Previous post When Rails Ejected Node and the History of Compiled JS in Rails
Next post Hot Glue v0.4.7