Rails World '26: Herb and ReActionView

Rails World '26: Herb and ReActionView

I watched Marco Roth’s talk at Rails World 2026, and it left me excited about where the Rails view layer is headed.

Marco has spent the last couple of years building Herb, an HTML-aware ERB parser that is on its way into Rails 8.2 core, and at Rails World he showed what he is building on top of it: A project called ReActionView opens a new window .

Marco Roth presenting on stage at Rails World 2026, in front of a large screen showing the glowing 'Rails World' logo

ReActionView adds real reactivity to your existing .html.erb templates, no Hotwire, no Stimulus, no JavaScript you have to write yourself. That is the part that got me.

Hotwire already does a lot for us, but it still asks you to write a Stimulus controller once the interaction gets specific, and Marco’s demo showed a page that updates itself because the server understands the template better than an ERB compiler ever has.

In this article, I will cover what Marco showed at Rails World: how ReActionView builds on Herb, why the view layer needed this, how it fits next to Hotwire and the wider field of server-driven reactivity, and what shipped in the release he pushed out the same day as the talk.

From Herb to ReActionView

A slide from the talk showing a sprig of herb leaves next to the Ruby on Rails logo, split down the middle like a two-color flag

We already wrote about Herb opens a new window itself, the HTML-aware ERB parser that was merged into Rails core on August 25, 2026 opens a new window and is on track to become Rails 8.2’s opt-in view engine.

This post is focused on what comes next. If you’d like more background on Herb itself, including the parser internals, the CLI, and what we found running it against a real codebase, our earlier post goes into all of that in more detail.

ReActionView is Marco’s separate project, and it predates the Rails merge.

He launched it at Rails World 2025 opens a new window alongside Herb::Engine and Herb’s dev tools opens a new window , as an ActionView-compatible engine you could adopt ahead of Rails itself.

Reactive templates, the part of ReActionView this talk was actually about, followed in 2026.

The split that matters now: Rails 8.2 takes Herb::Engine itself into the framework, so an app running 8.2’s defaults compiles .html.erb templates through Herb without installing anything.

ReActionView is what is left over, the validators, the error overlays, the dev tools, the instrumentation, and reactive templates. The two compose. You can run vanilla Rails 8.2 and get the parser.

You add ReActionView on top when you want your templates to do something with that HTML-aware understanding of themselves.

The View Layer in Rails

Rails has spent two decades getting good at scaling the parts of the stack behind the template: database indexes, background jobs, caching layers, horizontal scaling of app servers.

The view layer’s answer to “make this interactive,” by comparison, has mostly stayed the same since Turbo and Stimulus arrived. That approach works well for individual interactions, but the complexity can add up as an application grows.

ReActionView’s own docs put the failure mode plainly: “a small interaction grows its own controller, its own endpoint and its own copy of the markup.”

A menu that opens, a row that reorders, a filter that narrows a list, each one is a small thing on its own, and each one asks you to duplicate logic that already exists in the ERB template that renders the page in the first place.

Multiply that by however many small interactions a real app accumulates, and the JavaScript layer becomes its own thing to maintain, with its own copy of the truth the server template already had.

ReActionView’s bet is that a parser that already understands your HTML and your embedded Ruby as one tree is the right place to close that gap, because it can answer questions about a template, what does this depend on, what changed, where does this state reach, that a plain ERB compiler never could.

A slide reading 'Your existing HTML+ERB views are now reactive,' with HTML+ERB highlighted in green

How ReActionView Compares to Stimulus and Turbo

ReActionView does not replace Turbo or Stimulus. Its own docs are explicit about it: “Turbo still drives navigation, and Stimulus is still the place for behavior that is more than writing a value.”

If you already reach for a Stimulus controller and it fits, keep writing it.

ReActionView is aimed at the smaller, more common case, a value on the page that changes, and everything that reads it should update, without a controller of its own.

That same problem, HTML rendered on the server that needs to react to state without a hand-written client, is one plenty of other frameworks have answered before ReActionView existed.

Phoenix LiveView keeps a live process per connection and pushes DOM diffs over a websocket.

Laravel Livewire wires a Blade template to server-side component state through polling requests.

Inertia.js takes the opposite approach and hands the view entirely to a client-side framework, while still routing through your server-side controllers.

ReActionView’s answer is narrower than any of those: Stay inside the .html.erb template you already have, and let the same controller action you already wrote answer when the browser needs it.

Diagram of where ReActionView sits in the Rails view layer: in the browser, Turbo handles navigation and full or partial page swaps, and Stimulus still handles hand-written behavior beyond a single value, while a new ReActionView runtime watches state and actions declared in the template; on the server, the same controller action and the same .html.erb template (parsed by Herb::Engine into one HTML and Ruby syntax tree) answer both a normal request with format=html, returning full page markup that Turbo swaps in, and a state-change request with format=slots and a Herb-State header, returning JSON of only the changed values that ReActionView patches into the DOM

A gradient, not a rewrite

What actually ships is a handful of independent steps, and adopting ReActionView means picking how far down that list you want to go, not signing up for all of it at once.

The docs lay it out as five steps:

  1. Herb finds what is wrong with your templates, in the browser while you develop and in your editor through the language server. This step is running the moment Rails compiles your templates with Herb, before you have touched a single reactive feature.

  2. Debug mode and the dev tools show which template rendered which element, what each render cost, and the queries a tag ran.

  3. State and actions turn a menu, a composer, or a tab into a declaration in the template and an attribute on an element, with no JavaScript of your own.

  4. The server answers. A select that re-sorts a list, or a form that adds a row, sends the new state back to the same controller action you already wrote, and only what changed on the page updates.

  5. Deferring what is slow. An <Async> block leaves its content out of the first response, so the page arrives immediately and the slow part follows once it is ready.

A slide showing an Async block wrapping a slow Stats.slow_query call, with a Fallback block rendering a skeleton placeholder paragraph until the async content is ready

<Async>
  <p><%= Stats.slow_query %></p>

  <Fallback>
    <p class="skeleton">&nbsp;</p>
  </Fallback>
</Async>

The skeleton paragraph renders immediately. Once Stats.slow_query resolves, ReActionView swaps it in, no polling or manual JavaScript required.

A concrete version of step 4:

Declare the state at the top of a template:

<%# herb:state (order: "oldest") %>

Read order in a <select> and in the list’s sort. Your controller reads the same value back:

herb_state("order", "oldest")

Change the select, and the client sends GET /messages?format=slots with a Herb-State header carrying the browser’s current state. Your index action runs exactly as it does for a normal page load, ReActionView renders the same template in a JSON slots format instead of HTML, and the client moves the rows that changed.

No new endpoint, no second copy of the sorting logic.

What shipped the day of the talk

ReActionView v0.6.0 went out the same day as the talk opens a new window , alongside Herb v0.11 opens a new window .

The release notes read like a direct answer to “reactive templates are still experimental, here is what got sturdier this cycle”:

  • The Herb-State header and the slots response format described above, so a template can serve a request the values it asked for instead of full HTML.

  • A map of what each piece of state on a page reaches, so the client knows what to touch when a value changes.

  • The Herb dev server wired in for slot-aware hot reload, so editing a template with reactive state in it does not require a full page refresh to see the change.

  • Built-in instrumentation that measures what a page actually did on a given render.

  • A dedicated error page served when a template fails to compile, instead of Rails’ generic error screen.

  • The client runtime distributed as the reactionview npm package, for teams that want it in their own JavaScript build instead of the asset pipeline default.

Reactive templates still carry a warning in the docs: the markup, the payload, and the JavaScript API can change between releases. Validation, debug mode, and the dev tools do not depend on any of that and are safe to run today.

Conclusion

Herb gives Rails 8.2 a parser that understands HTML and Ruby as one tree. ReActionView is Marco’s bet on what that understanding is good for beyond linting: closing the gap between “the server already knows this” and “so I wrote a Stimulus controller and an endpoint to say it again.”

It does not ask you to leave ERB, adopt a client framework, or give up Turbo and Stimulus for the interactions they already handle well. It asks you to declare a little more in the template you already have, and see how far down the gradient you want to go.

Are you weighing how Herb, ReActionView, or the rest of the Rails 8.2 view layer fits into your product’s roadmap? If your app isn’t ready for Rails 8.2 yet, talk to us about getting it there opens a new window .

Get the book