I’m trying to pass a received slot (list) to another component within a HEEx template. Here’s the closest working example I have:
slot :foo do
attr :bar, :string, required: true
end
def parent(assigns) do
~H"""
<.child>
<:foo :for={foo <- @foo} {foo}>
<%= if foo.inner_block, do: render_slot(foo) %>
</:foo>
</.child>
"""
end
slot :foo do
attr :bar, :string, required: true
end
def child(assigns) do
~H"""
<span :for={foo <- @foo} attr-bar={foo.bar}>
<%= if foo.inner_block, do: render_slot(foo), else: "default" %>
</span>
"""
end
# usage
<.child>
<:foo bar="1">foo</:foo> # <span attr-bar="1">foo</span>
<:foo bar="2"/> # <span attr-bar="2">default</span>
</.child>
<.parent>
<:foo bar="1">foo</:foo> # <span attr-bar="1">foo</span>
<:foo bar="2"/> # <span attr-bar="2"></span>
</.parent>
The issue with this solution is that the parent component always generates an inner_block for the slot. This solution is not valid if you need slots without inner_block
An alternative solution:
def parent(assigns) do
~H"""
<.child>
<:foo :for={foo <- @foo} :if={is_nil(foo.inner_block)} {foo}/>
<:foo :for={foo <- @foo} :if={not is_nil(foo.inner_block)} {foo}>
<%= if foo.inner_block, do: render_slot(foo) %>
</:foo>
</.child>
"""
end
In this case, we can replicate the inner_block == nil. However, the slot order gets disrupted, which isn’t ideal as the order is often crucial.
Additionally, an older solution from this thread where the slot is passed as an attribute doesn’t seem to work with LiveView 0.21.1.
Is there a way to seamlessly send a slot (or a list of slots) to a child component that I might have missed? Wrapper components can be very helpful! Any guidance would be much appreciated.