I’m building a Finnish electricity price-tracking dashboard https://sahkotanaan.fi/. I’m trying to stick to a majestic monolith approach, but I’m hitting a wall regarding the best way to handle the highly interactive parts of the UI.
The core of the site isn’t just displaying charts; it relies heavily on interactive calculators. A user can drag a slider to input their specific contract margin, toggle their heating type, and type in their estimated consumption. The UI needs to instantly calculate their cost based on the live hourly spot price.
I want to keep this as strictly “Rails” as possible, but I need these calculators to feel absolutely instant.
For those of you building math-heavy, highly interactive UI components like this in Rails 7+:
Do you use Stimulus to pull the hourly price from a data attribute and do all the math locally in the browser so it’s instant?
Do you use Turbo Streams and send a request to the server on every slider movement/input change? (My worry here is network latency making the slider feel jerky).
Do you abandon Hotwire for these specific, highly reactive components and just mount a lightweight Vue or React component on the page?
I really want to avoid introducing a frontend build step if I don’t have to, but I don’t want the user experience of the calculators to suffer. How are you all handling this kind of localized, complex state?
I would probably go for Stimulus in this case (so option 1). Option 2 could indeed have latency issues, and I think option 3 would add a lot of incidental complexity (but that may depend on how comfortable you are with Vue or React).
Based on what you described, Stimulus would be just fine. The “hourly spot price” could potentially be sent over a stream to be up to date, but if just hourly a pull on page load might be enough.
I would be pragmatic here: If you already have prior use of a reactive framework in the project I would use that, since this kind of problem would indeed fit the reactive style well.
But if the rest of the project is vanilla Rails, I wouldn’t add another framework just for this and I’d stick with Stimulus. Done well, the code will be really clean.
I don’t know what you’re aiming for but based on your link, I might do something like this:
Wrap the whole interactive area into a parent stimulus controller that has the sole purpose of coordinating the smaller controllers.
The main controller is responsible for storing the base values. All widgets that manipulate values use data-action to call methods on the main controller to update the base values.
Each UI element that needs to update how it looks based on changing values is wrapped in its own small controller. These controllers are all mounted as outlets on the main controller.
When the main controller has a value updated, it in turns updates stimulus values on all of the relevant outlets.
The outlets have a Stimulus value changed callback defined that updates how it looks.
That way the main controller owns the values but the rendering is modular, in outlets, and flow of updates is clear.
This is just an idea to get you thinking, your actual optimal setup will almost certainly be very different!