Basecamp's new Stimulus 1.0 JavaScript framework targets a modern take on HTML pages augmented with light amounts of JavaScript, rather than the creation of full-featured JavaScript applications. Basecamp calls it "modest JavaScript framework for the HTML you already have."

Prior to Stimulus, the Basecamp team used a variety of techniques and libraries such as jQuery for building Basecamp. However, they did not have a comprehensive solution, and found their codebase had too many disparate patterns which presented difficulties for consistency, reuse, and onboarding new team members. The Basecamp 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.

The single-page application (SPA) architectural style have gained in popularity within the JavaScript community as they provide more responsive user interactions, do not have a flash of white between page loads, and preserve JavaScript libraries in memory. Stimulus aims to retain the benefits of single page applications by building on another library, Turbolinks, which intercepts links and loads new HTML views via background HTTP requests via a persistent process. Turbolinks descends from pjax, an approach developed by GitHub. The main difference compared to most frameworks is that Stimulus loads new HTML fragments generated from the server rather than converting JSON data into new HTML on the client side.

Stimulus differs from most universal or isomorphic JavaScript frameworks in that its focus remains on loading new HTML views, whereas most isomorphic frameworks use server-side rendering only for the initial page view.

Stimulus delivers three main concepts — controllers, actions, and targets — and progressively enhances HTML with these features. Developers begin with HTML with some custom attributes:

<!--HTML from anywhere--> <div data-controller="hello"> <input data-target="hello.name" type="text"> <button data-action="click->hello#greet"> Greet </button> <span data-target="hello.output"> </span> </div>

And then write a controller to act upon that HTML:

// hello_controller.js import { Controller } from "stimulus" export default class extends Controller { static targets = [ "name", "output" ] greet() { this.outputTarget.textContent = `Hello, ${this.nameTarget.value}!` } }

Basecamp CTO and Ruby on Rails creator David Heinemeier Hansson elaborates:

Stimulus is concerned with manipulating this existing HTML document. Sometimes that means adding a CSS class that hides an element or animates it or highlights it. Sometimes it means re-arranging elements in groupings. Sometimes it means manipulating the content of an element, like when we transform UTC times that can be cached into local times that can be displayed. There are cases where you’d want Stimulus to create new DOM elements, and you’re definitely free to do that. We might even add some sugar to make it easier in the future. But it’s the minority use case. The focus is on manipulating, not creating elements.

In many ways, Stimulus is a modern throwback to the simpler days of a decade ago, when frameworks did not assume complete control of the web application, create and render the DOM, and track state. Its primary focus is for content websites that need a bit of progressive enhancement, rather than full-fledged JavaScript web applications.

Zufrizal Yordan, software engineer at HOOQ, commented on Twitter that:

What I like about Stimulus ... is they do progressive enhancement instead of serving UI via JS. Sometimes it’s easier to do it this way. Different people, different approach. Good to hear someone isn't going full JS compared to the trend right now.

In contrast with some smaller JavaScript frameworks, Stimulus is authored in TypeScript.

The Basecamp team chose TypeScript for several reasons including pleasant type annotations, tooling, refactoring, preventing bugs, classes, code completion, and inline documentation. Basecamp engineer Sam Stephenson explained to InfoQ the benefits in leveraging TypeScript:

First, the types are there in my code anyway, whether I write them out or not. TypeScript's optional annotations just make the editing and refactoring process more pleasant. I like to compose classes without tightly coupling them by using Cocoa-style delegate interfaces. TypeScript's interface system is useful here because the compiler and editor can give me a sort of to-do list of methods to write at implementation time.

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