Getting started


  • Components are subclasses of ViewComponent::Base and live in app/components. It’s common practice to create and inherit from an ApplicationComponent that’s a subclass of ViewComponent::Base.
  • Component names end in -Component.
  • Component module names are plural, as for controllers and jobs: Users::AvatarComponent
  • Name components for what they render, not what they accept. (AvatarComponent instead of UserComponent)


In Gemfile, add:

gem "view_component"

Quick start

Use the component generator to create a new ViewComponent.

The generator accepts a component name and a list of arguments:

bin/rails generate component Example title

      invoke  test_unit
      create  test/components/example_component_test.rb
      create  app/components/example_component.rb
      create  app/components/example_component.html.erb

Available options to customize the generator are documented on the Generators page.


A ViewComponent is a Ruby class that inherits from ViewComponent::Base:

class ExampleComponent < ViewComponent::Base
  erb_template <<-ERB
    <span title="<%= @title %>"><%= content %></span>

  def initialize(title:)
    @title = title

Content passed to a ViewComponent as a block is captured and assigned to the content accessor.

Rendered in a view as:

<%= render( "my title")) do %>
  Hello, World!
<% end %>


<span title="my title">Hello, World!</span>


Since 2.31.0

String content can also be passed to a ViewComponent by calling #with_content:

<%= render( "my title").with_content("Hello, World!")) %>

Rendering from controllers

It’s also possible to render ViewComponents in controllers:

def show
  render( "My Title"))

Note: Content can’t be passed to a component via a block in controllers. Instead, use with_content. In versions of Rails < 6.1, rendering a ViewComponent from a controller doesn’t include the layout.

When using turbo frames with turbo-rails, set content_type as text/html:

def create
  render(, content_type: "text/html")

Rendering ViewComponents to strings inside controller actions

When rendering the same component multiple times for later reuse, use render_in:

class PagesController < ApplicationController
  def index
    # Doesn't work: triggers a `AbstractController::DoubleRenderError`
    # @reusable_icon = render"close")

    # Doesn't work: renders the whole index view as a string
    # @reusable_icon = render_to_string"close")

    # Works: renders the component as a string
    @reusable_icon ="close").render_in(view_context)