ViewComponent has multiple methods to render ERB (or Slim) and HTML. Initially, when ViewComponent was released, there were two options, a:
- separate html.erb file, and;
- call method.
But since v3.0 there is another strategy you can use: erb_template. It essentially works the same as the call method, but also allows ERB or plain HTML. The goal for both call and erb_template is to eliminate an extra file. Keeping your component to one file only. Tidy and neat!
The three different rendering strategies
Let’s go over how each one works and then I give some guidelines to help you choose.
erb.html
This is the default way where the template is defined in a separate .html.erb file located in the same directory as the component class. In this file you can write any ERB or HTML you need.
# app/components/example_component.html.erb
<h1>Hello, <%= @name %>!</h1>
call
The call method can be used to write the rendering logic directly in Ruby component file. It’s the option that can render HTML using Rails’ ActionView content_tag
or tag
helpers or any other Ruby code.
# app/components/example_component.rb
class ExampleComponent < BaseComponent
def initialize(name:)
@name = name
end
def call
content_tag(:h1, "Hello, #{@name}")
end
end
erb_template
You can view the erb_template strategy as a merge of the above two strategies. You can write the same HTML + ERB as with html.erb file.
# app/components/example_component.rb
class ExampleComponent < BaseComponent
def initialize(name:)
@name = name
end
erb_template <<~ERB
<h1>Hello, <%= @name %>!</h1>
ERB
end
See that weird-looking <<~ERB
? In Ruby it is called a “squiggly heredoc” and it allows for writing multi-line strings with automatic indentation removal.
You can of course also use other templating engines, Slim for example. That would look like this:
# …
slim_template <<~SLIM
<h1>Hello, <%= @name %>!</h1>
SLIM
# …
Which strategy to use?
So which strategy to use when? Over the few years of writing ViewComponent and building a UI Components library with it, I’ve build up some best practices when to use which strategy.
I use this as a guideline (as always with guidelines, change when it makes sense based on the context).
- one line of content, eg.
content_tag(:h1, "Hello, #{@name}")
usecall
; - between 2 and 11 lines; use
erb_template
; - more than 12 lines; use
html.erb
.
Where do I get these numbers from? Besides number 1, pretty much out of thin air. The rationale is that anything beyond 10 lines makes the component file feel more cluttered. Tucking it away in another file helps here (if you can’t see it, it isn’t there!). The reality is that I nowadays (since the introduction of erb_template
) mostly use that strategy.
Your mileage may vary. Maybe you choose a range between 2 and 19. Fine by me! Agree on a number between yourself/your team and use that as a guideline. But having a guideline give you something to reason about.
Anything I overlooked? Something different you use? Let me know.