Stimulus, the “JavaScript Framework for the HTML You Already Have”, Releases 2.0

Stimulus, which self-describes as a “modest JavaScript framework for the HTML you already have” recently released its second major iteration. Stimulus inspired Catalyst, GitHub’s web component set of patterns.

Next to all-encompassing frameworks that grow to accommodate an ever larger set of concerns (e.g., client-side rendering, server-side rendering, routing, componentization, internationalization), Stimulus decidedly assumes a contained scope:

Stimulus is a JavaScript framework with modest ambitions. It doesn’t seek to take over your entire front-end—in fact, it’s not concerned with rendering HTML at all. Instead, it’s designed to augment your HTML with just enough behavior to make it shine.

Stimulus uses HTML sources that are annotated with controller, target, and action attributes. Those annotations are mapped according to pre-defined conventions to existing JavaScript code in a way that seeks to minimize the amount of JavaScript necessary to add interactivity to a page.

The documentation page provides the following example of HTML source:



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

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

  <span data-hello-target="output">
  </span>
</div>

That HTML source is mapped to the following JavaScript code:



import  Controller  from "stimulus"

export default class extends Controller 
  static targets = [ "name", "output" ]

  greet() 
    this.outputTarget.textContent =
      `Hello, $this.nameTarget.value!`
  


The data-controller indicates to Stimulus that the corresponding DOM element will be handled by the hello_controller.js script. data-actions (here click->hello#greet) have Stimulus provisioning a click event handler (greet method of the hello controller) on the corresponding DOM element. Stimulus additionally allows mapping important elements to controller properties. The controller having a reference to those elements may then update or inspect those elements according to the desired logic. The data-hello-target attributes in the previous sample code thus reference a name and output DOM elements available respectively as this.nameTarget and this.outputTarget in the hello controller.

Setting up event handlers that trigger some actions that in response update some DOM elements is a fundamental part of the behavior of interactive web applications. Stimulus thus takes a shorter path compared to other frameworks by directly mapping in the source HTML the DOM elements to the JavaScript that impacts them.

There may, as a result, be less glue code to write. Stimulus may be viewed by some as a simpler alternative to fully-featured front-end framework with higher-level abstractions (e.g., virtual DOM, templating system, reactive values). While those frameworks, to a large extent, predicate separating application state from the DOM, sometimes even duplicating DOM state in custom data structures (virtual DOM), Stimulus rather relies on the DOM to hold pieces of application state, and encourages direct updates and inspection of DOM elements.

Stimulus’ concept of controller will be familiar to users of Rails and Laravel. Stimulus originates from some of the developers who created Rails. Direct DOM updates and using DOM state as the source of truth will equally be familiar to long-time programmers who started web development with jQuery and jQuery plugins. The Basecamp team behind Stimulus reported using in the past a variety of techniques and libraries such as jQuery for building Basecamp. The team commented that the variety of patterns used prevented consistency, reuse, and onboarding of new team members. The team felt that most modern frameworks were not focused on solving the problems they had at Basecamp, where HTML is front and center and JavaScript is there to assist, rather than the reverse.

John Beatty, the author of tutorials for Stimulus, argued:

How many web pages actually need a JS framework?


Most don’t. They just need sprinkles of interactivity. Stimulus.js provides the modern JavaScript framework to provide interactivity your user’s crave, without needing to relegate you Rails app to a JSON API.

Ruby on Rails creator David Heinemeier Hansson however emphasized that Stimulus does not fit every need:

Stimulus is concerned with manipulating this existing HTML document. […] There are cases where you’d want Stimulus to create new DOM elements, and you’re definitely free to do that. […] But it’s the minority use case. The focus is on manipulating, not creating elements.


Stimulus […] work great in conjunction with other, heavier approaches. If 80% of your application does not warrant the big rig, consider using our two-pack punch for that. Then roll out the heavy machinery for the part of your application that can really benefit from it. […]


Above all, it’s a toolkit for small teams who want to compete on fidelity and reach with much larger teams using more laborious, mainstream approaches.

One InfoQ reader, Leon Mika, presented on his blog a summary of his experience with Stimulus and concluded as follows:

The tag-line on the site, A modest JavaScript framework for the HTML you already have, is true to its word. […]


So, if you have a web-app with server-side rendering, and you need something a bit more — but not too much more — than what jQuery or native DOM provides, this JavaScript framework might be worth a look.

GitHub quoted Stimulus as a source of inspiration for Catalyst, a set of patterns used at GitHub to make developing complex applications with web components easier. The three core Catalyst concepts (Observe, Listen, Query) adapt the three core Stimulus concepts (controllers, actions, and targets) to a context with custom elements.

Stimulus 2.0 builds on the previous version, fixes some bugs, and deprecates the data map API from Stimulus 1.0. Stimulus 2.0 additionally supports DOM event listener options and adds values and CSS classes APIs.

Stimulus is available under the MIT open source license and is available on GitHub.