A Stimulus Way of Doing Things
Recently, I stumbled across a minimalistic framework for building interactive front-end UI - Stimulus. Probably every good front-end developer knows about React, majority knows about Vue.js, some people know Svelte or many hate Angular. All of those frameworks have one thing in common: they are used mainly to build SPA (single-page application).
SPA
Single-page application is a concept where the whole UI is built inside a web browser. The whole JavaScript with all of the HTML and CSS is loaded additionally to the browser's first response and then executed. The main page before JavaScript is executed contains only one empty <div/>
inside a <body/>
. All scripts that need to be loaded are linked inside <head/>
tag. This concept has its benefits, like everything is loaded once, all of the JavaScript and other sources can be cached via CDN and the whole communication with the back-end is done via AJAX with JSON data. JSON data saves some bandwidth if it is on a highly loaded server and is natively used inside JavaScript. But it also has some drawbacks. You need to build a web page with a different architecture, you need to design an API, you need to take into account SEO (many crawlers simply don't execute JavaScript and only see a blank page), also you need to be security conscious about what data you want to pass to the browser and you need to write a lot of JavaScript beside your back-end code.
Stimulus
And here comes Stimulus to the rescue!
Stimulus by itself is not used to build SPA, has all the reactivity needed, is easy to use and can be used with your already existing code. Simply add some data-
attributes to your HTML code, create a JavaScript file with a Controller
, add some logic and you're done! Here is some example from Stimulus' page that shows written text from an <input/>
inside a <span/>
element.
<!--HTML from anywhere-->
<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>
import {Controller} from '@hotwired/stimulus';
export default class extends Controller {
static targets = ['name', 'output'];
greet() {
this.outputTarget.textContent = `Hello, ${this.nameTarget.value}!`;
}
}
Stimulus also contains user defined values, contains watchers for those values (i.e. methods with value's name and suffixed with ValueChanged
, e.g. value with a name count
executes on change a method called countValueChanged
), has mechanism to call user defined actions on HTML events, supports custom event dispatching to communicate with other controllers or uses web browser's MutationObserver
API to automatically update all Controller
instances. There is everything a developer needs to build a nice reactive UI without the need to build a SPA. You can also use a library like htmx or Turbo to replace snippets of HTML code via AJAX, which can contain Stimulus data-
attributes that are automatically used by Stimulus.
The days when we used to use jQuery
or simple JavaScript code to attach listeners when HTML document
was ready
and execute some logic after user clicks on an element are long gone.
The main benefit is, that we can preserve existing back-end code, we can still use battle-tested HTML templating libraries, we do not need to add another complex library or redesign our application's architecture and we do not need to write too much JavaScript.
Here is also an example of a counter with a watcher.
<div data-controller="counter">
<button data-action="counter#increment">Click me!</button>
<p data-counter-target="message">Your click count: 0</p>
</div>
import {Controller} from '@hotwired/stimulus';
export default class extends Controller {
static values = {
counter: Number,
};
static targets = [
'button',
'message',
];
increment() {
this.counterValue++;
}
counterValueChanged(newValue) {
this.messageTarget.textContent = `Your click count: ${newValue}`;
}
}
Neat!
Conclusion
We have seen that there are some simpler lightweight alternatives to robust front-end frameworks to build web applications like Stimulus. It contains all the important functionalities to build a robust UI and is actively maintained on GitHub. Recently it was updated to version 3.1.0 with some nice new features, like :prevent
or :stop
action options to automatically call preventDefault
or stopPropagation
when a certain event is called without explicitly specifying it in our action. You can read more about this framework in their documentation.