A component starts out as an ERB file.
Take text_field.component.erb
<% attr_accessor: :value %>
<input type="text" value="<%= value %>" %>Herb then compiles this into a class, which can be instantiated and called to render ERB:
# That ERB above is precompiled by Herb and becomes a class
class HerbComponents::TextField
attr_accessor :value
def initialize(value:)
# ...
end
def render(&block)
# Herb's converted ERB output
end
endNeed to include some modules? herb_mix to the rescue
<% herb_mix(
include_modules: [ApplicationHelper, CustomHelper, SomeUnrelatedModule]
) %>
<% attr_accessor: :value %>
<input type="text" value="<%= value %>" %>Dealing with a complex component? You can:
- Specify a parent class:
<% herb_mix(
parent_class: MyComplexPORO
) %>
<%# ERB All the way %># That ERB above is precompiled by Herb and becomes a class
class MyComponent < MyComplexPORO
attr_accessor :value
def initialize(value:)
# ...
end
def render(&block)
# Herb's converted ERB output
end
end- Define the class inside of the component?
<% herb_class do
def supports?
# ...
end
%>
<%# More ERB %>semi_complex.component.erb
# That ERB above is precompiled by Herb and becomes a class
class HerbComponents::SemiComplex
# ...
def supports?
# ...
end
def render(&block)
# Herb's converted ERB output
end
endrender_component(:text_field) => `HerbComponents::TextField.new.render`
render_component(:text_field, value: 1234) => `HerbComponents::TextField.new(value: 1234).render`
render_component(:text_field, value: 1234) {|component| ... } => `HerbComponents::TextField.new(value: 1234).render{ |component| ... }`Basically: Try to DRY up creating components; since ViewComponents generate a lot of boilerplate (especially with sidecar files). Since Herb's parser gives you a combined HTML + RB tree, you can compile it into the method that's used to render.