Lazy-loading content with Turbo Frames and skeleton loader
Tags: ruby, rails, tailwindcss, webdev
Published: 2021-03-30 13:49:25

---
title: Lazy-loading content with Turbo Frames and skeleton loader
published: true
date: 2021-03-30 13:00:00 UTC
tags: ruby,rails,tailwind,webdev
canonical_url: https://boringrails.com/tips/turboframe-lazy-load-skeleton
---

[Hotwire](https://hotwire.dev/) is a new suite of frontend tools from Basecamp for building “reactive Rails” apps while writing a minimal amount of JavaScript.

While the most exciting feature to some is the real-time streaming of server rendered HTML, my favorite addition is the [Turbo Frame](https://turbo.hotwire.dev/reference/frames).

The Turbo Frame is a super-charged iFrame that doesn’t make you cringe when you use it. Frames represent a slice of your page and have their own navigation context.

One incredibly powerful feature is lazy-loading a Frame. One example of this pattern that you probably see everyday is the GitHub activity feed:

![GitHub Activity Feed: Lazy load](https://boringrails.com/images/github-feed.gif)

First you load the “outer shell” of the page and then you can make an AJAX call to fetch more content to fill in the rest of the page. It’s a great way to speed up a slow page.

But one downside is that the page content jumps around a bit. The “Loading” spinner is one small rectangle, but the result is a long feed of events.

A way to solve this problem is to use a [“skeleton screen” or “skeleton loader”](https://uxdesign.cc/what-you-should-know-about-skeleton-screens-a820c45a571a). This UI pattern uses a blank version of the content as a placeholder and reduces the jarring impact when the content finally loads.

![Skeleton loader](https://boringrails.com/images/skeleton-loader.png)

These two concepts go together like peanut butter and jelly.

## Usage

A basic lazy-loaded Turbo Frame looks like this:

```html
<turbo-frame id="feed" src="/feed">
  Content will be replaced when /feed has been loaded.
</turbo-frame>
```

By specifying the `src` attribute, the Frame will automatically make an AJAX request when the page loads and replace its content with the matching `<turbo-frame>` in the response.

Additionally, you can set the `loading` property of the loading to be either “eager” (load right away) or “lazy” (load once the frame is visible on the page).

Here’s how the GitHub Activity feed might look in a Rails view:

```ruby
<%= turbo_frame_tag :feed, src: activity_feed_path, loading: :lazy do %>
  Loading...
<% end %>
```

You can take it to the next level by replacing the basic “Loading…” message with your own skeleton loader. Tailwind makes this really easy with the built-in `animate-pulse` class.

Simply add some gray rectangles as your initial frame contents:

```ruby
<%= turbo_frame_tag :feed, src: activity_feed_path, loading: :lazy do %>
  <div class="flex flex-col space-y-6">
    <% 10.times do %>
      <div class="animate-pulse flex space-x-4">
        <!-- Avatar -->
        <div class="rounded-full bg-gray-400 h-12 w-12"></div>

        <!-- Details -->
        <div class="flex-1 space-y-4 py-1">
          <div class="h-4 bg-gray-400 rounded w-3/4"></div>
          <div class="space-y-2">
            <div class="h-4 bg-gray-400 rounded"></div>
            <div class="h-4 bg-gray-400 rounded w-5/6"></div>
          </div>
        </div>
      </div>
    <% end %>
  </div>
<% end %>
```

Once you wrap your head around the power of Turbo Frames, soon you’ll be spotting all kinds of places in your app that can benefit from lazy-loading some good old HTML.

## Additional Resources

Hotwire Docs: [Turbo Frames](https://turbo.hotwire.dev/reference/frames)

Tailwind Docs: [animate-pulse](https://tailwindcss.com/docs/animation#pulse)

* * *
[![](https://boringrails.com/images/twitter-banner.png)](https://twitter.com/_swanson)