ViewComponent/view_component · error · ViewComponent::ContentSlotNameError

COMPONENT declares a slot named content, which is a reserved

Error message

COMPONENT declares a slot named content, which is a reserved word in ViewComponent.

Content passed to a ViewComponent as a block is captured and assigned to the `content` accessor without having to create an explicit slot.

To fix this issue, either use the `content` accessor directly or choose a different slot name.

What it means

Raised when a singular slot name is exactly :content (lib/view_component/slotable.rb:318-320). ViewComponent captures any block passed at the call site into the built-in content accessor, so a slot named content would collide with that accessor and make the intent ambiguous. The error tells the developer to use the content accessor directly or to pick another name.

Source

Thrown at lib/view_component/slotable.rb:319

        end

        slot
      end

      def __vc_validate_plural_slot_name(slot_name)
        if RESERVED_NAMES[:plural].include?(slot_name.to_sym)
          raise ReservedPluralSlotNameError.new(name, slot_name)
        end

        __vc_raise_if_slot_name_uncountable(slot_name)
        __vc_raise_if_slot_conflicts_with_call(slot_name)
        __vc_raise_if_slot_ends_with_question_mark(slot_name)
        __vc_raise_if_slot_registered(slot_name)
      end

      def __vc_validate_singular_slot_name(slot_name)
        if slot_name.to_sym == :content
          raise ContentSlotNameError.new(name)
        end

        if RESERVED_NAMES[:singular].include?(slot_name.to_sym)
          raise ReservedSingularSlotNameError.new(name, slot_name)
        end

        __vc_raise_if_slot_conflicts_with_call(slot_name)
        __vc_raise_if_slot_ends_with_question_mark(slot_name)
        __vc_raise_if_slot_registered(slot_name)
      end

      def __vc_raise_if_slot_registered(slot_name)
        if registered_slots.key?(slot_name)
          raise RedefinedSlotError.new(name, slot_name)
        end
      end

      def __vc_raise_if_slot_ends_with_question_mark(slot_name)

View on GitHub (pinned to 9f22c36fa7)

Solutions

  1. Rename the slot to describe what it holds, for example :body, :summary or :description
  2. Drop the slot and rely on the built-in content accessor: pass a block at the call site and read content in the template
  3. Use content.present? in the template when the component needs optional content with a fallback

Example fix

# before
class PanelComponent < ViewComponent::Base
  renders_one :content # raises ContentSlotNameError
end

# after
class PanelComponent < ViewComponent::Base
  renders_one :body
end
# template reads body, or the built-in content accessor
Defensive patterns

Strategy: validation

Validate before calling

def slot_name_available?(name)
  name.to_sym != :content
end

slot_name_available?(:content) # => false

Try / catch

# config-driven registration only
begin
  renders_one(dynamic_name.to_sym)
rescue ViewComponent::ContentSlotNameError
  dynamic_name = :body
  retry
end

Prevention

When it happens

Trigger: renders_one :content, and renders_many :content, whose singularized form is also :content and is validated at lib/view_component/slotable.rb:151. renders_many :contents instead hits the plural reserved list first and raises ReservedPluralSlotNameError.

Common situations: An optional rich text area named content; components migrated from partials that had a content local; developers combining a content slot with the with_content helper, which is exactly the overlap the framework prevents.

Related errors


AI-assisted analysis of ViewComponent/view_component@9f22c36fa7 (2026-08-23). Data as JSON: /api/errors/a012a6fabc2951f7. Report an issue: GitHub.