Templates

ViewComponents wrap a template (or several, if using variants), defined in one of several ways:

Sibling file

The simplest option is to place the view next to the Ruby component:

app/components
├── ...
├── example_component.rb
├── example_component.html.erb
├── ...

Subdirectory

Since 2.7.0

As an alternative, views and other assets can be placed in a subdirectory with the same name as the component:

app/components
├── ...
├── example_component.rb
├── example_component
|   ├── example_component.html.erb
├── ...

To generate a component with a sidecar directory, use the --sidecar flag:

bin/rails generate component Example title --sidecar
  invoke  test_unit
  create  test/components/example_component_test.rb
  create  app/components/example_component.rb
  create  app/components/example_component/example_component.html.erb

#call

Since 1.16.0

ViewComponents can render without a template file, by defining a call method:

# app/components/inline_component.rb
class InlineComponent < ViewComponent::Base
  def call
    if active?
      link_to "Cancel integration", integration_path, method: :delete
    else
      link_to "Integrate now!", integration_path
    end
  end
end

It’s also possible to define methods for Action Pack variants (phone in this case):

class InlineVariantComponent < ViewComponent::Base
  def call_phone
    link_to "Phone", phone_path
  end

  def call
    link_to "Default", default_path
  end
end

Note: call_* methods must be public.

Inline

Since 3.0.0

To define a template inside a component, include the experimental ViewComponent::InlineTemplate module and call the .TEMPLATE_HANDLER_template macro:

class InlineErbComponent < ViewComponent::Base
  include ViewComponent::InlineTemplate

  attr_reader :name

  erb_template <<~ERB
    <h1>Hello, <%= name %>!</h1>
  ERB

  def initialize(name)
    @name = name
  end
end

Inherited

Since 2.19.0

Component subclasses inherit the parent component’s template if they don’t define their own template.

# If MyLinkComponent doesn't define a template,
# it will fall back to the `LinkComponent` template.
class MyLinkComponent < LinkComponent
end

Rendering parent templates

Since 2.55.0

To render a parent component’s template from a subclass, call render_parent:

<%# my_link_component.html.erb %>
<div class="base-component-template">
  <% render_parent %>
</div>

Trailing whitespace

Code editors commonly add a trailing newline character to source files in keeping with the Unix standard. Including trailing whitespace in component templates can result in unwanted whitespace in the HTML, eg. if the component is rendered before the period at the end of a sentence.

To strip trailing whitespace from component templates, use the strip_trailing_whitespace class method.

class MyComponent < ViewComponent::Base
  # do strip whitespace
  strip_trailing_whitespace

  # don't strip whitespace
  strip_trailing_whitespace(false)
end