Sprinkling StimulusJS - Light JS Without Heavy Choices.

sprinkling-stimulus

Introduction

In today’s state of web applications, it can be hard to choose the right tool to imbue your web pages with bits of interactivity. There is an immense number of options that you can take, but unfortunately, many of them require you to commit to a comprehensive javascript framework. This decision to commit I believe should not be taken lightly especially if you are making this choice for your team/company/business.

The way I often handle these decisions is to not avoid making them at all. Decision fatigue and the stress it brings is are real.

In an evasive attitude of risk, I discovered StimulusJS as a possible option that fit some of the use cases. In this article, I share my experience with it in creating an interactive password input form with requirements being shown as being satisfied or not on user typing and my thoughts on it.

Sprinkle Stimulus

As the authors mentioned, the goal of Stimulus is to sprinkle pages with JS to make them sparkle. If you primarily have server-side rendered HTML pages and you want to imbue some interactivity on them, then it might be a good fit for your project. Otherwise, you might want to find another tool.

The core concepts specifically mention that it is mainly meant to bind onto existing HTML and manipulating them. It is not concerned with creating HTML to render like React does.

For instance:

// In Stimulus
<div data-controller="clipboard">
  PIN: <input data-target="clipboard.source" type="text" value="1234" readonly>
  <button data-action="clipboard#copy">Copy to Clipboard</button>
</div>
// In React
<pin-input></pin-input>

In the Stimulus approach, you’d see all the HTML up front and might avoid having to dig into another file to see what HTML would be. However, this could mean your HTML files can get larger and run the risk of being unmanageable.

StimulusJS Is Pretty Easy To Learn

As a person who spends most of their time working in the backend, I found that the documentation was clear and easy to digest. I was able to get the main premise of it and enough information to use it fairly quickly. I spent about an hour (or so) with the documentation and was able to be productive with it.

Building An Interactive Password Input Field With Requirements

In my pursuit of learning, I created a basic password input field that shows the requirements beneath it in an interactive manner. The requirements beneath are toggled to be satisfied or not satisfied upon user input. You can see the source code here and test it live here.

A demo gif of it - Demo of password requirements field

Here is are snippets derived from the code that demonstrates it working together (with some code removed for brevity):

import { Controller } from "stimulus";

class PasswordInputController extends Controller {
  static targets = [
    "lowercaseLetter"
    // Removed other targets for brevity.
  ]

  connect() {
    this.validatePassword();
  }

  onInput(event) {
    this.password = event.target.value;
  }

  set password(value) {
    this.data.set("password", value);
    this.validatePassword();
  }

  get password() {
    if (!this.data.has("password")) {
      this.password = "";
    }

    return this.data.get("password")
  }

  validatePassword() {

    // Validate lowercase letters
    let lowerCaseLetters = /[a-z]/g;
    if (this.password.match(lowerCaseLetters)) {
      this.lowercaseLetterTarget.classList.toggle('invalid', false);
    } else {
      this.lowercaseLetterTarget.classList.toggle('invalid', true);
    }

    // Removed code on other validations of brevity
  }

}

export { PasswordInputController }
<div data-controller="password-input">
  <input class="input" type="password" data-action="input->password-input#onInput"></input>

  <li data-target="password-input.lowercaseLetter" class="password-requirements__requirement">
    At least one lowercase letter
  </li>
  <!-- Remove Code For Brevity -->
</div>

The PasswordInputController defines the logic that runs in relation to the HTML that it will be bound to. The Controller class provided by Stimulus, gives us the ability to have sections of logic to run upon binding via connect() and on user input defined by onInput() and the data-action="input->password-input#onInput" attribute on the input element. A validatePassword() function is defined to add/remove the invalid CSS class of the corresponding li elements via the data-target attribute. This function is called initially by connect() and also within the setter of password.

Through this, I was able to produce a functional password input field.

Testing?

I found that testing the controllers made via Stimulus was not as simple as I would have liked.

I initially ran into some issues trying to get the stimulus controllers to run in due to missing MutationObserver. This was remedied by a post by Hrvoje Šimić.

Unfortunately, there are not many resources related to how to testing. However, a issue had been opened recently to request for added documentation in the official webpage.

Admittedly, my struggles with getting the tests setup might be rooted in my inexperience.

Conclusion

Stimulus is a great tool that can be used to make your HTML pages “sparkle” with interactivity without having to commit to a framework. It was fairly easy and approachable to learn how to utilize the Stimulus.

If you find yourself needing to add a little bit of interactivity onto your predominantly server-side HTML rendered application, you might find salvation in choosing to use Stimulus.