Rails Progress Indicator for Turbolinks Using Nprogress

Contrary to popular opinion, I’m a fan of Turbolinks. I leave it enabled in all my Rails applications. Most of the negative opinions I hear relate to it “breaking” third-party jQuery plugins. I say “breaking” because it’s not really changing the plugin’s behavior – just requires the plugin to be initialized differently.

If you’re upgrading to a newer version of Rails and have a bunch of legacy JavaScript code, I can imagine this being difficult. But if you’re green-fielding a new application, there’s no reason not to take advantage of it. I wrote extensively about how to organize JavaScript in a Rails application with Turbolinks enabled. If you’re struggling to get your JavaScript code to work as expected on clicks through the application, take a look at that post. I continue to use that organization pattern for all my applications and it never lets me down.

With Turbolinks enabled, interacting with an application feels smooth and fast. No more full page refreshes.

Every once in awhile we’ll stumble on a page request takes longer than others. Rather than having the user sit there thinking nothing is happening, we can offer better feedback through a loading progress bar, specifically nprogress. I’ve found it to be the perfect companion to Turbolinks to create a great user experience.

The Problem

In a traditional web application, when we click a link or submit a form, we get a loading spinner where the favicon typically appears. We might also see text in the status bar saying “Connecting…” or “Loading…”. These are the loading indications that internet users have become accustomed to.

By adopting Turbolinks, we not longer get those loading feedback mechanisms because the request for the new page is asynchronous. Once the request is complete, the new content is rendered in place of the previous page’s body element. For fast page loads, this isn’t a problem. However, if you have applications like mine, every once in awhile, you might have a page request take a few seconds (reasons for this are beyond the scope of this article). In those cases, a user might click a link and sit there for 2-3 sec. without any indication the page is loading. While Turbolinks generally improves the user experience of our application, having no user feedback for several seconds is not ideal (ideally, you’d want to address a page request that takes multiple seconds). This is where nprogress can help.

The Solution

nprogress is a progress loading indicator, like what you see on YouTube.

Like other JavaScript libraries, there’s a Ruby Gem that vendors the code and includes it in the Rails asset pipeline.

We’ll first add nprogress-rails to our Gemfile:

gem "nprogress-rails"

Bundle to install the new gem:

$ bundle install

Now with nprogress installed, we need to include the JavaScript in our application. We’ll do this by adding the following the app/assets/javascripts/application.js manifest:

//= require nprogress
//= require nprogress-turbolinks

We first include the nprogress JavaScript source, and then an adapter that’ll hook the Turbolinks request to the progress indicator.

Note: If you’re familiar with Turbolinks and its events, you’ll recognize the events triggered.

By default, the nprogress loading bar is anchored to the top of the browser window, but we need to include some CSS to make this work. Let’s open the app/assets/stylesheets/application.scss manifest file and add the following:

*= require nprogress
*= require nprogress-bootstrap

Note: Including nprogress-bootstrap isn’t necessary if you don’t use Bootstrap in your application. I typically do, so I’m going to include it.

At this point, we’ll have a working loading indicator. But what if we want to tweak the styles to match your application’s theme?

Customizing Nprogress Styles

Because the nprgress styles are Sass, we can overwrite the variables for customization.

There are 3 variables available to overwite:

  • $nprogress-color
  • $nprogress-height
  • $nprogress-zindex

For Bark, we have an aqua accent color with use throughout the site. It made sense for the nprogress loading indicator to be that same color.

Back in our app/assets/stylesheets/application.scss, I overwrote the variable before including the nprogress source code:

$nprogress-color: #37c8c9;

@import "nprogress";
@import "nprogress-bootstrap";

Summary

I’ve found nprogress to be a great companion library to Turbolinks. The two libraries together provide a much better user experience over full page refreshes. Turbolinks helps asynchronously load the page content that’s changing and nprogress gives the user feedback that their request is in progress. Now, even when a user has to suffer through multi-second page loads, at least they’ll know it’s not broken and don’t have to click again.

The latest version of Turbolinks has a progress bar built-in. I’m looking forward to removing the dependency if it performs similarly.