Skip to main content Link Search Menu Expand Document (external link)

Slots V1 (deprecated)

Slots V1 is now deprecated and will be removed in 3.0. Please migrate to Slots V2

Slots enable multiple blocks of content to be passed to a single ViewComponent, reducing the need for sub-components (for example ModalHeader, ModalBody).

By default, slots can be rendered once per component. They provide an accessor with the name of the slot (#header) that returns an instance of ViewComponent::Slot, etc.

Slots declared with collection: true can be rendered multiple times. They provide an accessor with the pluralized name of the slot (#rows), which is an Array of ViewComponent::Slot instances.

To learn more about the design of the Slots API, see #348 and #325.

Defining Slots

Slots are defined by with_slot:

with_slot :header

To define a collection slot, add collection: true:

with_slot :row, collection: true

To define a slot with a custom Ruby class, pass class_name:

with_slot :body, class_name: 'BodySlot'

Note: Slot classes must be subclasses of ViewComponent::Slot.

Example ViewComponent with Slots

# box_component.rb
class BoxComponent < ViewComponent::Base
  include ViewComponent::Slotable

  with_slot :body, :footer
  with_slot :header, class_name: "Header"
  with_slot :row, collection: true, class_name: "Row"

  class Header < ViewComponent::Slot
    def initialize(classes: "")
      @classes = classes

    def classes
      "Box-header #{@classes}"

  class Row < ViewComponent::Slot
    def initialize(theme: :gray)
      @theme = theme

    def theme_class_name
      case @theme
      when :gray
      when :hover_gray
      when :yellow
      when :blue
      when :hover_blue
<%# box_component.html.erb %>
<div class="Box">
  <% if header %>
    <div class="<%= header.classes %>">
      <%= header.content %>
  <% end %>
  <% if body %>
    <div class="Box-body">
      <%= body.content %>
  <% end %>
  <% if rows.any? %>
      <% rows.each do |row| %>
        <li class="Box-row <%= row.theme_class_name %>">
          <%= row.content %>
      <% end %>
  <% end %>
  <% if footer %>
    <div class="Box-footer">
      <%= footer.content %>
  <% end %>

# index.html.erb

<%= render( do |component| %>
  <% component.slot(:header, classes: "my-class-name") do %>
    This is my header!
  <% end %>
  <% component.slot(:body) do %>
    This is the body.
  <% end %>
  <% component.slot(:row) do %>
    Row one
  <% end %>
  <% component.slot(:row, theme: :yellow) do %>
    Yellow row
  <% end %>
  <% component.slot(:footer) do %>
    This is the footer.
  <% end %>
<% end %>