Sergio Xalambrí

Use NProgress in a Remix app

Remix's philosophy is to kill all the spinner! This is amazing, but sometimes it's not possible. Connections may be slow, actions can't be cached, etc.

This is why Remix also gives you a useTransition hook to know when a transition is happening and create a loading state. And we can combine it with NProgress to build a friendly and straightforward-looking loading indicator.

First, install NProgress.

npm i nprogress
npm i -D @types/nprogress # if you are using TS, also run this

Then in your root route, import it together with their CSS and useTransition.

import NProgress from "nprogress";
import nProgressStyles from "nprogress/nprogress.css";
import { useTransition } from "remix";

Now, export a links function with the stylesheet link.

export let links: LinksFunction = () => {
  // if you already have one only add this stylesheet to your list of links
  return [{ rel: "stylesheet", href: nProgressStyles }];

In finally, in the the default export, your component, add this lines:

let transition = useTransition();

let fetchers = useFetchers();

 * This gets the state of every fetcher active on the app and combine it with
 * the state of the global transition (Link and Form), then use them to
 * determine if the app is idle or if it's loading.
 * Here we consider both loading and submitting as loading.
let state = useMemo<"idle" | "loading">(
  function getGlobalState() {
    let states = [
      transition.state, => fetcher.state),
    if (states.every((state) => state === "idle")) return "idle";
    return "loading";
  [transition.state, fetchers]

React.useEffect(() => {
  // and when it's something else it means it's either submitting a form or
  // waiting for the loaders of the next location so we start it
  if (state === "loading") NProgress.start();
  // when the state is idle then we can to complete the progress bar
  if (state === "idle") NProgress.done();
}, [transition.state]);

And that's it, now every time you submit a form or click a link, it will show the progress bar at the top of the page.