How To Remove Empty Turbo Frame Space
I recently ran into an annoying layout quirk while building an ‘infinite-scroll’ type interface. The page loads data lazily as you scroll through a long list of posts, which works beautifully when there is indeed data to display. But in the scenario where there are no posts, the empty Turbo Frame was still claiming space in the layout, creating awkward gaps in the interface.
The solution turned out to be remarkably simple, thanks to Tailwind’s empty: modifier. By adding empty:hidden to the Turbo Frame tag, the frame completely disappears from the layout when it contains no child elements.
Here’s what the lazy-loading frame looks like in the parent view:
<%= turbo_frame_tag dom_id(user, :posts),
loading: :lazy,
src: posts_path(user),
class: "empty:hidden" do %>
<% end %>
The key is that empty:hidden class. It tells the browser to hide the frame entirely when it has no children, which is exactly what happens when there’s no data to display.
On the response side, you conditionally render content inside the frame:
<%= turbo_frame_tag dom_id(@user, :posts) do %>
<% if @posts.any? %>
<!-- Your posts content here -->
<% end %>
<% end %>
When @posts is empty, the frame renders with no children as tailwind’s empty:hidden class kicks in, and the frame is removed from the layout flow entirely. No more phantom spacing and no more janky layouts.
This pattern works great for lazy-loaded content where some items might legitimately have no data. The frames that do have content render normally, while the empty ones simply vanish. It’s a small detail, but it makes the interface feel much more polished.