Stimulus: A modest JavaScript framework for the HTML you already have
Published on by Paul Redmond
The team over at Basecamp has released a new Javascript framework (v1.0.0) called Stimulus, available as of January 30th. Stimulus is quite a departure from some of the more popular frontend JavaScript frameworks, touting more separation of concerns between your HTML’s content and behavior:
Stimulus is a JavaScript framework with modest ambitions. Unlike other frameworks, Stimulus doesn’t take over your application’s entire front-end. Rather, it’s designed to augment your HTML by connecting elements to JavaScript objects automatically.
The documentation explains that the separation between your HTML’s behavior and content is bridged by data-controller
‘s from HTML to JavaScript.
Here’s a simple example, which I believe is pretty straightforward:
<div data-controller="hello"> <input type="text"> <button data-action="click->hello#greet">Greet</button></div>
Here’s the hello
controller code:
// src/controllers/hello_controller.jsimport { Controller } from "stimulus" export default class extends Controller { greet() { console.log("Hello, Stimulus!", this.element) }}
The data-action="click->hello#greet"
button attribute is the ticket here; you can break down the value as follows:
-
click
is the event name -
hello
is the controller identifier -
greet
is the name of the method to invoke
We can mark important elements as a target to reference them in the controller:
<div data-controller="hello"> <input data-target="hello.name" type="text"> <button data-action="click->hello#greet">Greet</button></div>
The data-target
value is the controller name and the target name. Here’s how you would reference this value in a controller:
// src/controllers/hello_controller.jsimport { Controller } from "stimulus" export default class extends Controller { static targets = [ "name" ] greet() { const element = this.nameTarget const name = element.value console.log(`Hello, ${name}!`) }}
Since this is a JavaScript class, we can benefit from a name
getter:
// src/controllers/hello_controller.jsimport { Controller } from "stimulus" export default class extends Controller { static targets = [ "name" ] greet() { console.log(`Hello, ${this.name}!`) } get name() { return this.nameTarget.value }}
These samples are from the Hello Stimulus introduction. Stimulus also works with Turbolinks out-of-the-box, which is useful for speeding traditional server-side applications.
You should check out the installation guide and the stimulus starter to get started with the framework.
Using Stimulus With Laravel
I also started experimenting with Stimulus, Turbolinks, and Laravel in a quick GitHub repository paulredmond/stimulus-laravel-demo. Here’s the gist of everything I needed to do to get it running:
yarn add stimulus turbolinksyarn add --dev babel-plugin-transform-class-properties
Add the following to your .babelrc
file in the root of the project:
{ "plugins": ["transform-class-properties"], "presets": [ ["env", { "modules": false }] ]}
Next, create a resources/assets/js/controllers
folder and replace the following in the resources/assets/js/app.js
file:
var Turbolinks = require("turbolinks")Turbolinks.start() import { Application } from "stimulus"import { definitionsFromContext } from "stimulus/webpack-helpers" const application = Application.start()const context = require.context("./controllers", true, /\.js$/)application.load(definitionsFromContext(context))
One last important note:
Turbolinks needs to be in the <head>
of the HTML document. The <body>
gets replaced when you navigate after getting the document via XHR, thus, the script needs to be outside of the <body>
tag.
So just add your app.js
file in the head like this:
<head> <!-- ... --> <link href="{{ mix('css/app.css') }}" rel="stylesheet" type="text/css" /> <script src="{{ mix('js/app.js') }}"></script></head>
Cheers!