Premise Stimulus controllers usually talk to each other via dispatched events. That works great for fire-and-forget notifications, but events have no return channel. Sometimes you want a request/response shape instead: ask a controller a question, wait for the answer, act on it. Enter the deferred-promise pattern. The trick is simple: create a promise, stash its resolve function on the controller…
Premise Here’s a pattern you’ll find in any app with inline-editable fields: change a value, auto-save it, show a little toast that confirms the save. It feels polished when it works. The problem is where that toast comes from. The standard Hotwire approach is to let the server send the toast back as a Turbo Stream, something like turbo_stream.append "toast" . That works, but the feedback is tied…
Premise This is the third installment in our View Transitions series. In Challenge 35 we built swiper-like page transitions with Turbo Drive, and in Challenge 38 we animated list appends with Turbo Streams. What we haven’t covered yet is the shared element transition , the one you know from native apps where a thumbnail in a grid smoothly morphs into the hero image on the detail page. The View…
Premise You’ve seen it: a Turbo Frame request hits a 500, and instead of anything useful, the user gets “Content Missing.” Or worse - a network blip leaves a lazy-loaded frame silently empty. No feedback, no way to recover. React solved this years ago with Error Boundaries - a wrapper component that catches failures in its children and renders fallback UI. We can do the same thing in Hotwire with…
Premise In Challenge 19 — building on Challenge 8 (inline stream tags) and Challenge 9 (custom actions) — we stored ephemeral state in localStorage. That worked, but the browser’s Back and Forward buttons don’t know about it. Hit Back after switching versions three times? You leave the page entirely. history.pushState() fixes this — but the part most people overlook is the first argument: the…
Premise Pick a country, then pick a city — you’ve seen this pattern a thousand times. The second dropdown depends on what you chose in the first. In jQuery-land this meant fetching JSON and manually rebuilding <option> elements. In React, you’d manage loading states, store the fetched options in component state, and re-render. With Turbo Frames, the server just re-renders the HTML you already…
Premise In the Loading Spinner challenge, we added busy indicators for Turbo Frame navigations — links that swap frame content asynchronously. But what about forms? When a user submits a form inside a Turbo Frame, Turbo handles the request and swaps the response, but gives zero visual feedback while it’s in flight. The button stays clickable, nothing changes on screen, and the user is left…
Premise Turbo Frames are a great way to compartmentalize your user interface, but sometimes they require workarounds when it comes to state management. One example of such a requirement is when you have to handle a form on your page that refers to <input> ’s in separate <turbo-frame> s. Starting Point We’re building upon the Faceted Search with Stimulus and Turbo Frames challenge here, but add a…
Premise Asynchronously loading content via Turbo Frames sometimes comes with a user experience degradation because the frame doesn’t advertise its busy status, and/or becomes unresponsive. Starting Point We start with a quite simplistic page that has a bullet point navigation and a Turbo Frame for the contents: <ul> <li><a href= "/page1" data-turbo-frame= "async-loader" > Load Page 1 </a></li>…
Premise Among the more esoteric native browser APIs there’s one that is mostly overlooked (well, tbh most of them are) and thus lead to a whole host of third-party solutions when in fact the browser already includes this capability out of the box: The Web Share API , which allows a site to share text, files, and URLs in a simple, standardized manner. Note : Of course, there’s a caveat - Firefox…