Optimizing for less code with UJS and data-behavior

UJS is a small javascript library that manages interactions with endpoints implementing SJR (Server-generated Javascript Responses), in addition to providing a few behaviors such as non-GET HTTP verbs for links, simple confirm UIs, and the disabling of elements with optional loading text while remote requests are processing. UJS and SJR are a fantastic solution for keeping a web application’s frontend code minimal, in an age where wild over-engineering in this area is increasingly the norm.

UJS behavior binding is declarative, and happens via data attributes (for instance you can use the attribute-value pair data-disable-with='Processing' to disable a submit button with the loading text “Processing” during a form POST).

For all that is great about UJS, one thing that it does not offer is any formal suggestion of a practice for introducing your own custom unobtrusive javascript behaviors to your application. For this we need to look beyond the library and to the broader developer community surrounding Rails and UJS. Javan Makhmali gave an excellent talk in which he features some screenshots of the Basecamp project tree and various code snippets. In this talk he introduces the convention of binding to custom unobtrusive javascript via data-behavior attributes.

Consider an e-commerce application wherein we want to pop open a shopping cart and place it into a loading state on certain interactions (clicking an “Add to Cart” button, adjusting item quantities). This shared behavior can have a very minimal, unobtrusive javascript implementation such as the following:

Note: we use jQuery’s ajaxSuccess event for our success handling instead of UJS’s ajax:success, because that event does not fire on elements if replaced by logic in SJR responses, and in this particular scenario we may want to bind to such elements.

We can now bind this behavior in a way which is both very readable, unambiguous and unobtrusive, i.e. from an “Add to Cart” link:

…or from an item quantity control:

I put together a small sample project demonstrating the custom UJS behavior described in this article, which you can find on GitHub. This project uses no javascript beyond stock UJS, SJR, and the simple 5-line snippet above, and it implements a UI which you can see in the video below:

I hope that this post, the above video and the linked demo project together give you a strong sense of just how much UJS, SJR and the data-behavior binding convention let you achieve while keeping your codebase both extremely minimal and highly legible, and that you keep these tools top-of-mind when evaluating possible paths for frontend architecture.


Hi! I'm Nicholas and I like building stuff. I spent a decade working with startups in NYC as a developer before turning my attention to seed-stage investing beginning in 2018. I write here on topics including startups, investing, travel, software development, and just about any other matter of personal relevance. I can be reached by email at [email protected].

No Comments

Leave a Comment

Please be polite. We appreciate that.
Your email address will not be published and required fields are marked