Is it possible for a Phlex component to yield more than once? For example:

class Component < Phlex::HTML
 def template
   div do
     yield
     span { plain "component" }
     yield
   end
 end
end

# Expected usage:
<%= render Component.new do %>
 <div>foo</div>
 <!-- "component" span should appear here -->
 <div>bar</div>
<% end %>

Obviously, this doesn’t work – the whole block just gets repeated. But is there a way to make it behave as expected, ideally without manually passing the content in pieces?

Why This Doesn’t Work:

Ruby blocks are not generators. When you yield, Ruby calls the entire block – it doesn’t pause and resume like JavaScript’s yield or Python’s yield in generators.

So yielding multiple times simply re-renders the full block each time.

Solution 1: Split the Content Using Named Blocks

You can simulate multiple-yield behavior by splitting your content manually into named lambdas and passing them to your component:

class Component < Phlex::HTML
 def initialize(first:, last:)
   @first = first
   @last = last
 end

 def template
   div do
     instance_exec(&@first)
     span { "component" }
     instance_exec(&@last)
   end
 end
end

Usage:

<%= render Component.new( first: -> { div { "foo" } },
 last:  -> { div { "bar" } }
) %>

Clean and reusable. Great if your component needs to handle dynamic regions or slots.

Solution 2: Yield self and Call Helper Methods Inside the Block

This is a clean Phlex-friendly pattern: let the block yield the component itself, so users can call methods like content at specific points.

Component:

class Component < Phlex::HTML
 def template
   div do
     yield(self)
   end
 end

 def content
   span { "component" }
 end
end

Usage:

<%= render Component.new do |c| %>
foo
<%= c.content %>
bar
<% end %>

This keeps your components tidy and gives callers full control over when to render specific bits of UI.

Solution 3: Use capture and unsafe_raw in ERB (Rails Only)

For Rails + ERB users, you can pre-capture content and pass it to your component:

Component:

class Component < Phlex::HTML
 def initialize(first:, last:)
   @first = first
   @last = last
 end

 def template
   div do
     unsafe_raw @first
     span { "component" }
     unsafe_raw @last
   end
 end
end

Usage:

<% first = capture do %>
foo
<% end %> <% last = capture do %>
bar
<% end %> <%= render Component.new(first: first, last: last) %>

Only use unsafe_raw if you’re confident the content is safe from injection.

My Recommended Solution

Use yield(self) and let the caller insert helper methods inside the block.

This gives the developer the flexibility to insert your reusable bits (span, content, etc.) at any point, while keeping a very readable and testable API:

class Component < Phlex::HTML
 def template
   div do
     yield(self)
   end
 end
 def content
   span { "component" }
 end
end

It’s concise, scalable, and aligns with how Ruby and Phlex both operate.

Summary Table

Approach Multiple Content Points Phlex DSL Friendly Readability Comments
Multiple yields to same block ❌ (Repeats content) ✅ ✅ Not recommended
Named lambdas âś… âś… âś… Best for slots-style API
capture + unsafe_raw ✅ ⚠️ ⚠️ Rails-only, careful with safety
yield(self) + helper method âś… âś… âś…âś… âś… Recommended

Final Thoughts

While Ruby blocks can’t pause and resume like generators, Phlex gives you enough flexibility to work around it elegantly. Whether you use lambdas, yield the component, or go with slots, you’ve got great tools to keep your view logic clean and composable.

If you’re building something more advanced like modal slots, tabs, or layout wrappers, consider building on the “named lambda” or yield(self) pattern, they scale really well.

Need Help With Ruby On Rails Development?

Work with our skilled Ruby on Rails developers to accelerate your project and boost its performance.

Hire Ruby on Rails Developer

Support On Demand!

Related Q&A