Question
ViewComponents are great, but rendering them is not pleasant.
Compared to Rails helpers, I find the syntax of ViewComponents quite verbose…
<%= render(HeadingComponent.new(level: 1)) do %>
My title
<% end %>
Is there any better solution that is easier to read/write?
For example:
component :heading
heading_component
- or something similar.
Answer
You can definitely use Rails helpers for syntactic sugar.
In particular, we have found a solution that we really like.
First you need to add this file to your Rails application:
module ComponentsHelper
COMPONENTS = Dir.glob(Rails.root.join('app', 'components', '*_component.rb'))
COMPONENTS.each do |filename|
name = File.basename filename, '_component.rb'
helper = "x_#{name}"
component = "#{name}_component".camelize.constantize
define_method(helper) do |*args, **kwargs, &block|
render(component.new(*args, **kwargs), &block)
end
end
end
Then you can use all your components with this simple, short syntax:
<%= x_heading level: 1 do %>
My title
<% end %>
This is especially nice - and easy to read - when you have many components or nested components. This original code for example:
<%= render(HeadingComponent.new(level: 1)) do %>
<%= render(IconComponent.new('user')) %>
<%= current_user.name %>
<%= render(SecondaryTextComponent.new(color: 'gray')) do %>
<%= current_user.email %>
<% end %>
<% end %>
Becomes this:
<%= x_heading level: 1 do %>
<%= x_icon 'user' %>
<%= current_user.name %>
<%= x_secondary_text color: 'gray' do %>
<%= current_user.email %>
<% end %>
<% end %>
If you read a page filled with view components, you will notice a great difference in readability.
The x
prefix should be read like “custom element”. For example a nav
helper may render a nav tag, while x_nav
renders your own nav with your application style (e.g. with Tailwind classes). Similar conventions are already used by other frameworks, like Blade.
The prefix also prevents possible collisions between the component helpers generated automatically and normal helpers.
Also x_nav
is actually easy to search across all your files, compared to the nav
keyword.
Also note that these helpers don’t remove any features from the original gem: you can still use all the components features, including slots.
It’s syntactic sugar and I think that it’s worth it.
This original solution is the one that we have built for AbstractBrain and Pushpad after a lot of research. It’s the closest solution that we found to React-style components using ERB and Rails.
Inspiring articles about this topic include: