LiveView Feels Faster With a Delayed Loading Indicator

This is a recipe about making your LiveView app feel faster. You can also make your app faster by running it on Fly.io. It only takes a few minutes.

LiveView is already fast. Couple that with hosting it on Fly.io where the server can be physically closer to your users and you've already got a great experience. However, the default setup for a new LiveView application displays the topbar progress indicator across the top of the page making the whole page feel like it's not ready. Here's a quick tip to make this so much better.

Problem

By default, LiveView ships with topbar to visually show that it's loading and setting up. The problem is, when I see a progress bar moving, my brain tells me "the page isn't ready yet". Even if that progress bar only takes 100 msec to quickly flash across the top, my brain still says, "the page isn't ready yet".

Notice the progress animation on the top of the page as we navigate around...

Before version with progress bar flashing

The page is fully rendered and I could start using the page, but it feels like I can't. Just because there's a quick flash of a progress bar on the top.

Why not just get rid of the progress display all together? Well, it's actually really helpful for those times when a page is taking longer to load for a user. In those situations, we want to let the user know there's a bit of work left to do.

So, if it's worth keeping the progress display, is there a way to make the topbar only display when it actually needs to? Can it only show if it's taking more time to setup the page?

Solution

Luckily, José Valim shared this tip and now it's documented in the LiveView Installation Guide. However, if you are like me, you already have a LiveView project that doesn't have this change. Fortunately, it's easy for us to do right now.

In less than 5 minutes I made the change and deployed my app. I now have a LiveView page that feels so much more responsive! Let's look at how to add this to an existing app.

In the project's app.js file, it might have a section that looks like this.

// Show progress bar on live navigation and form submits
topbar.config({barColors: {0: "#29d"}, shadowColor: "rgba(0, 0, 0, .3)"})
window.addEventListener("phx:page-loading-start", info => topbar.show())
window.addEventListener("phx:page-loading-stop", info => topbar.hide())

Replace that code with something like this:

// Show progress bar on live navigation and form submits. Only displays if still
// loading after 120 msec
topbar.config({barColors: {0: "#29d"}, shadowColor: "rgba(0, 0, 0, .3)"})

let topBarScheduled = undefined;
window.addEventListener("phx:page-loading-start", () => {
  if(!topBarScheduled) {
    topBarScheduled = setTimeout(() => topbar.show(), 120);
  };
});
window.addEventListener("phx:page-loading-stop", () => {
  clearTimeout(topBarScheduled);
  topBarScheduled = undefined;
  topbar.hide();
});

Basically, this only shows the topbar at all if it's taking longer than 120 msec to receive the phx:page-loading-stop event. So the progress bar is still shown if it takes more than 120 msec. You can play with the exact time delay to use. You could use 200 msec or other times as well.

We make the change, deploy the app, and see that the progress bar doesn't flash across as we navigate between different LiveView pages!

After version using delay before activating progress bar

Nice! It worked! That just feels so much better!

Discussion

The beauty of this solution is that my brain now has no progress bar movement making it feel like it's not ready.

The funny thing is, the page is quickly rendered and displayed to the user. Even if it takes 100 msec to setup the websocket and receive the phx:page-loading-stop event, as a visitor, I have just been presented with a whole new page.

It takes a moment for my brain to adjust and orient itself to the new page. Additionally, it takes a moment to move my mouse or my finger to actually interact with the page.

By the time I actually react, it's fully loaded and ready for me. This change makes it feel instantaneous. It's only perception, but perception is what makes it feel slow or fast.

If the page takes more time to setup, the topbar progress is displayed letting the user know. Most of the time though, the user will never see it.

Awesome! An easy win that makes my deployed, server-rendered, LiveView app feel like it's running locally on the user's machine.

That's a quick win I'll take any day!

Fly ❤️ Elixir

Fly is an awesome place to run your LiveView apps. It's really easy to get started. You can be running in minutes.

Deploy your Elixir app today!