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?
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.
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.
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.
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.
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.
| 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 |
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.
Work with our skilled Ruby on Rails developers to accelerate your project and boost its performance.
Hire Ruby on Rails Developer