Herb and ReactionView: Revolutionizing ERB templating in Rails
Are you tired of your ERB templates that look like a plate of spaghetti? Do you crave real feedback when your HTML goes haywire? Do you finally want to develop apps with React AND Rails natively?
During one of Rails World 2025's presentations, Marco Roth, a passionate full-stack developer and open source contributor, presented THE solution we've all been waiting for. In his talk, he unveils Herb, an HTML-aware ERB parser, and ReactionView, an ambitious initiative to modernize Rails' view layer without abandoning what makes the framework great.
In this article, you'll discover how these tools can transform your development experience, from automatic formatting of your templates to the possibility of integrating React or Vue components directly into your Rails views.
Buckle up, this is going to shake up your workflow!
The problem with ERB today
A parser that doesn't understand HTML
Since 2004, ActionView has hardly changed. It's stable, it's reliable, but... it's also limited. The current templating engine, eRuby, treats your .erb files as simple text files with bits of Ruby sprinkled in. The problem? It has no awareness of the HTML structure.
Let's take a concrete example. If you write this template:
A classic ERB parser would see this:
- An ERB tag (<% if ... %>)
- Some plain text
- Another ERB tag (<% end %>)
It doesn't understand that the if and the end form a logical structure wrapping an HTML element. It's like giving a book to someone who can only read individual words, without understanding sentences!
The everyday consequences
This limitation shows up as several frictions :
- No intelligent autocompletion: Your editor can't help you fill in the data-controller or data-action attributes for Stimulus
- No error detection: You forget a closing tag? You'll only know by opening the page in your browser
- Impossible formatting: Try automatically formatting a complex ERB file with Prettier... spoiler: it won't work
- Limited tooling: Tools like linters only work on pure HTML, not on Rails tag helpers (tag.div, content_tag, etc.)
For reference, a linter is a tool that analyzes your code to detect errors, inconsistencies and bad practices. It helps you keep a clean, consistent, and easier-to-maintain code style. Basically, it's like a spell checker, but for developers.
Herb: An ERB parser that understands HTML
Herb's architecture
Herb (HTML-aware ERB Parser) is the answer to all these problems. It's a complete ecosystem of tools built around a next-generation parser.
Here are its technical characteristics:
- Written in C: For maximum performance
- Based on Prism: The new official Ruby parser, to analyze Ruby code in your templates
- Cross-platform: Runs in Ruby (C extension), Node.js, JavaScript, and even in the browser
What makes Herb special is that it produces an interleaved syntax tree of HTML and Ruby. Unlike eRuby which sees disconnected pieces, Herb understands the full hierarchy.
Concrete parsing example
Let's revisit our previous example:
With Herb, the parser yields a structure like this:
Herb knows that the if and the end are linked. It knows that the
element is inside the conditional block. This structural understanding opens up infinite possibilities.
The tools of the Herb ecosystem
The automatic formatter
The first revolutionary tool is Herb Formatter. (Yes, a formatter that actually works for ERB! No, you're not dreaming.)
Is your code a mess? You save the file, and bam! The code is reformatted automatically with correct indentation and consistent spacing. And it works as well on pure HTML as on Rails tag helpers.
The intelligent linter
Herb Lint currently ships with 32 rules to detect common errors and enforce best practices. Here are a few examples:
- Detection of duplicate IDs: Herb can tell if you use the same id twice in your page (which is invalid HTML)
- 9 accessibility rules: To ensure your HTML is usable by everyone
- Structure validation: Detection of malformed closing tags, invalid nesting (such as <p> within <p>)
All of that with a beautifully colored CLI output that shows you exactly where the problem is.
Stimulus Lint: finally diagnostics for Stimulus!
Stimulus Lint is a dedicated package that extracts diagnostics from the Stimulus LSP (Language Server Protocol). Previously, these checks were available only in the editor. Now you can run them in CI/CD!
The package uses the Stimulus Parser and Herb to detect:
- Undefined Stimulus controllers
- Actions referencing non-existent methods
- Invalid targets
They also plan to develop a linter for Turbo in the future!
Tailwind Pretty: automatic class sorting
If you use Tailwind CSS (and let's be honest, who isn't in 2025?), you'll love Tailwind Pretty Plugin. It's the equivalent of Tailwind's official Prettier plugin, but works with Herb.
When you add Tailwind classes to your HTML elements and save, they automatically reorder according to the order recommended in Tailwind's documentation. And it also works on Rails' tag helpers!
ReactionView: Reinventing the Rails rendering engine
The starting observation
After building all these parsing tools, Marco asked himself a dizzying question: What if we used Herb to create a new rendering engine for Rails?
The current engine (eRuby/Erubi) compiles your templates using regular expressions. It breaks the template into chunks of text and Ruby, then concatenates them into a buffer. It's simple, but it doesn't take advantage of the document's structure.
How the Herb rendering engine works
The Herb rendering engine works differently. Here is the process:
- Parsing: The template is transformed into a syntax tree
- Tree traversal: A "visitor" walks each node (HTML elements, ERB tags, text)
- Optimized compilation: Consecutive nodes of the same type are merged before compilation
- Code generation: We produce a compiled template similar to Erubi's, but with the guarantee of valid HTML
The result? An engine compatible with the Erubi API, which you can plug into Rails without changing your existing code.
Automatic HTML validation
The community needed this new engine. Who hasn't spent far too long trying to figure out where the error in their HTML view comes from?
Take the example below where closing tags are missing
Rails will compile this code without hesitation. It doesn't care that the
tag isn't closed. You'll only discover the error later when inspecting the generated HTML.
With Herb? Boom! Immediate compilation error
Herb refuses to compile invalid HTML. It's like moving from a dynamically typed language to a language with static type checking, but for your templates.
Moreover, since Herb can decompose HTML nodes precisely, it can find exactly where the error is in your view, saving you a lot of mental energy.
The exact line, the exact column, with a little arrow pointing to the problem and a clear message. No more hunting for 10 minutes for a mis-closed tag!
Revolutionary debugging features
Visual annotations of templates
ActionView has a setting called annotate_rendered_view_with_filenames that adds HTML comments around your partials.

Nice and great, but with many partials it's not very practical. The problem? You can't style HTML comments.
Herb does better: it injects data-* attributes on your elements in development. Combined with a bit of CSS, you get colored outlines around each view, partial, and component.
- Blue for the main views
- Green for the partials
- Purple for the components
On hover, the full file path appears. And hold on: by clicking the outline, the file opens directly in your editor! It's like having devtools that talk directly to your IDE.
Added the debug tag
A bit more CSS
You get a clear, stylized view where your elements have a styled border. Handy, right? :)

Visualization of dynamic content
Even better! You can add a type
This lets you on a page with many components visualize them directly.

And if you add a "path" attribute to them, on hover you see the rendered value. By clicking, you jump directly to the file and the line where this expression is defined. No need to grep through your entire codebase to find where this mysterious text comes from!

Installation and usage
Getting started
To try Herb in your Rails application, it's ridiculously simple:
The generator creates an initializer. To enable interception of ERB templates:
Restart your server, and there you go! You now have:
- Precise error messages
- Visual template annotations
- Visualization of dynamic content
- Automatic HTML validation
Using the command-line tools
For formatting:
For linting:
It's as simple as that!
The ReactionView vision: Bridging the gap
The SPA vs SSR gap problem
Marco identifies a fundamental problem in the Rails ecosystem today: there is no middle ground between a traditional Rails app with Hotwire (server-side rendering) and a full SPA with a Rails API.

When a team wants more interactivity, more control, they often abandon everything and go SPA. It's all or nothing. Marco aims to create intermediate levels, progressive adoption stages.
The 6 adoption levels planned
ReactionView defines 6 levels to progressively evolve your application:
Level 1 & 2 (available today with Herb 0.7):
- HTML-aware rendering engine
- Automatic HTML validation
- Precise error messages
- Visual debug annotations
Level 3 (exploration):
- Internal ActionView optimizations
- Inlining partial calls
- Optimized rendering of tag helpers
- Increased performance
Level 4 (inspired by Phoenix LiveView):
- Intelligent diffing: Only re-render what changed
- State tracking before/after
- Element-level selective rendering
Level 5 (hybrid components):
- Ability to use React, Vue or Svelte components directly in ERB
- Client-side automatic hydration
- Passing props from the server
- Registering external libraries (like shadcn/ui)
Imagine being able to write this:
Level 6 (ultimate vision):
- Server components that can be transferred to the client (the inverse of React Server Components!)
- Component-scoped CSS (like Vue.js with <style scoped>)
- JavaScript scoped per view (like Svelte)
- Optimistic UI updates
- Improved offline operation
Example of scoped CSS
One of the ideas explored is the scoped CSS per view file, inspired by Vue.js:
The engine would transform this by adding unique data-* attributes:
Result: your styles never leak outside the component. Goodbye CSS class conflicts! I say a big yes, because debugging CSS is a pain after five minutes.
Why this matters for Rails
Keeping Rails attractive and modern
Marco makes his motivation very clear: Rails must stay attractive for new projects. Too many teams today choose to jump straight to SPAs because they think ActionView isn't powerful enough.
But abandoning ActionView means losing:
- Rails' incredible productivity
- Server-side rendering (better for SEO)
- The simplicity of not managing complex client state
- Natural integration with Active Record and the rest of the framework
ReactionView aims to prove you can have both: the simplicity of Rails AND the interactivity power of modern frameworks.
Embracing modern web standards
The web platform has evolved dramatically in recent years:
- Web Components for creating reusable elements
- Import Maps for loading ES6 modules
- View Transitions API for smooth page-to-page animations
- Popover API and Invoker Commands for interactivity with no JavaScript
- Container Queries, CSS Nesting and CSS Functions in CSS
Rails shouldn't ignore these advances. ReactionView proposes integrating them naturally into the Rails workflow.
An incremental approach
ReactionView's genius is that it doesn't break anything. The Herb engine is 100% compatible with Erubi. You can enable it in your existing application without changing a line of code. It's a perfect drop-in replacement.
And if something doesn't work? You disable the option and return to the classic engine. No painful migration, no giant refactoring.
Prism's impact and the domino effect
The Prism revolution for Ruby
Marco draws an interesting parallel with Prism, the new official Ruby parser. Prism revolutionized Ruby tooling by offering a standardized and performant AST (Abstract Syntax Tree). This enabled tools like the Ruby LSP to dramatically improve the developer experience in editors.
The same effect for templates
Herb aims to have the same impact for ERB templates:
- A standardized AST of HTML + ERB
- A common base for building tools
- High performance (thanks to C)
- Easy adoption thanks to compatibility
The idea is that other projects can build on Herb, in the same way they build on Prism today.
Limitations and next steps
Current state of the project
Let's be honest: ReactionView is still experimental. Marco presents it as a "vision talk", an exploration of what's possible. Levels 1 and 2 are ready for testing, but higher levels are still in the research phase.
How to contribute
The project is open source, and Marco actively encourages the community to:
- Test Herb in your applications: It's in production that real bugs are found
- Report issues: Open issues on GitHub if something doesn't work as expected
- Contribute code: The project accepts pull requests
- Share your feedback: Even if it's just "it works great" or "I don't see the point", feedback is valuable
- Star the project on GitHub: To give the project visibility
Useful links
Conclusion: The future of Rails' view layer
ReactionView may be just a vision today, but it's a necessary one. The web development landscape has changed, expectations have evolved, and Rails must adapt without losing its soul.
Herb and ReactionView show that it's possible to modernize ActionView while staying faithful to Rails' principles:
- Convention over configuration
- Good defaults
- Simplicity above all
- But with power when you need it
Marco Roth and the Herb contributors have already achieved something remarkable: proving that tooling for templates can be as good as for Ruby code. Visual annotations, automatic formatting, HTML validation... these are features we've been waiting for years.
So yes, installing reactionview, turning on intercept_erb = true, and seeing your template errors finally presented clearly, may be a small step. But it's a step in the right direction: toward a modern, powerful Rails that remains as delightful to use as ever.
The Ruby community has built incredible tools for the language itself. It's time to bring the same care to the view layer. And with Herb, we finally have the means. 🚀
Find Marco's full presentation below:
Rails Ascent