Pascal’s philosophy starts with the following ideals:
- we should be able to swap and replace the HTML on a page on a whim. We can then support techniques like pjax (replacing the whole body of a page with new HTML such as with Turbolinks) and ahah (asynchronous HTML over HTTP: replacing parts of a page with new HTML, so as to make our app feel really fast while still favouring server-generated HTML;
- favour native Browser APIs over proprietary libraries. Use the tools the browser gives us (History API, Custom Event handlers, native form elements, CSS and the cascade) and polyfill older browsers.
He argues that a single application can combine the options along the JS Gradient, but also that we need only move to a new level if and when we reach the current level’s threshold.
He defines the levels as follows:
- Global Sprinkles: general app-level enhancements that occur on most pages, achieved by adding event listeners at
documentlevel to catch user interactions and respond with small updates. Such updates might include dropdowns, fetching and inserting HTML fragments, and Ajax form submission. This might be achieved via a single, DIY script (or something like Trimmings) that is available globally and provides reusable utilities via
- Component Sprinkles: specific page component behaviour defined in individual
.jsfiles, where event listeners are still ideally set on the
- Stimulus components: where each component’s HTML holds its state and defines its behaviour, with a companion controller
.jsfile which wires up event handlers to elements;
- Spot View-Models: using a framework such as Vue or React only in specific spots, for situations where our needs are more complex and generating the HTML on the server would be impractical. Rather than taking over the whole page, this just augments a specific page section with a data-reactive view-model.
One point to which Pascal regularly returns is that it’s better to add event listeners to the
document (with a check to ensure the event occurred on the relevant element) rather than to the element itself. I already knew that Event Delegation is better for browser performance however Pascal’s point is that in the context of wanting to support swapping and replacing HTML on a whim, if event listeners are directly on the element but that element is replaced (or a duplicate added) then we would need to keep adding more event listeners. By contrast, this is not necessary when the event listener is added to the
Note: Stimulus applies event handlers to elements rather than the
document, however one of its USPs is that it’s set up so that as elements appear or disappear from the DOM, event handlers are automatically added and removed. This lets you swap and replace HTML as you need without having to manually define and redefine event handlers. He calls this Automated Behaviour Orchestration and notes that while adding event listeners to the
document is the ideal approach, the Stimulus approach is the next best thing.
Also of particular interest to me was his Stimulus-based Shopping Cart page demo where he employs some nice techniques including:
- multiple controllers within the same block of HTML;
- multiple Stimulus actions on a single element;
- controller action methods which use
document.dispatchEventto dispatch Custom Events as a means of communicating changes up to other components;
- an element with an action which listens for the above custom event occurring on the
document(as opposed to an event on the element itself).
I’ve written about Stimulus before and noted a few potential cons when considering complex interfaces, however Pascal’s demo has opened my eyes to additional possibilities.