Using Mantine NavigationProgress with Remix
Tags: javascript, tutorial, webdev, react
Published: 2022-07-28 19:19:56

Today we are going to learn how to implement the [NavigationProgress component from Mantine.dev](https://mantine.dev/others/nprogress/) in a remix application. The component will be used to indicate that there is some asynchronous process happening (loading content, navigating, form submission).

### Using `<NavigationProgress>`

Mantine has an additional package called `@mantine/nprogress` which contains a single component and some utility functions for interacting with the component state. If you haven't installed it already [follow the installation instructions first](https://mantine.dev/others/nprogress/).

We are only concerned with the functions `startNavigationProgress` to trigger the progress bar to start increasing and `resetNavigationProgress` to reset and hide the progress bar. We will hook these up to Remix so that we start progress any time the UI is in a loading or submission state and reset progress every time the UI returns to the idle state.

The component `<NavigationProgress>` by default renders a progress bar in a React Portal, this is fine if you are rendering at the top of the viewport but otherwise you may have to [adjust some of the default props](https://mantine.dev/others/nprogress/?t=props)

### Remix `useTransition` hook

Remix provides a [useTransition](https://remix.run/docs/en/v1/api/remix#usetransition) hook that exposes the current state of any loaders or actions in your application. The hook exposes quite a lot of data about the transition such as what type of transition it is, and what the next location will be, but we are only interested in the `state`. When there is no transition occurring `state` will be `"idle"` and otherwise it will be `"loading"` or `"submitting"` depending on the transition type.

### Implementing a `<GlobalLoadingIndicator>` component

Using this knowledge we can create a small component to link Remix transitions and NavigationProgress together.

```tsx
import { useEffect } from "react";
import { useTransition } from "@remix-run/react";
import {
  NavigationProgress,
  resetNavigationProgress,
  startNavigationProgress,
} from "@mantine/nprogress";

export const GlobalLoadingIndicator = () => {
  const { state } = useTransition();
  useEffect(() => {
    if (state === "idle") {
      // we are idle so hide the progress bar
      resetNavigationProgress();
    } else {
      // we are doing something so show the progress bar
      // and allow it to increment
      startNavigationProgress();
    }
  }, [state]);

  // I set the stepInterval to 100 so it increases every 100 milliseconds
  // but you can set it to something that feels nice for your app
  return <NavigationProgress stepInterval={100} />;
};
```

### Using your new component

The final step to include the progress bar in your app is to render the `<GlobalLoadingIndicator>` component in your layout somewhere that it can always be seen. In my case I render it inside the `<MantineProvider>` in `root.tsx`.

```tsx
    <html lang="en">
      <head>
        <Meta />
        <Links />
        <StylesPlaceholder />
      </head>
      <body style={{ margin: 0 }}>
        <MantineProvider
          theme={{ colorScheme: "light" }}
          withGlobalStyles
          withNormalizeCSS
        >
          {/* Your usage may differ */}
          <GlobalLoadingIndicator />
          <Outlet />
        </MantineProvider>
        <ScrollRestoration />
        <Scripts />
        <LiveReload />
      </body>
    </html>
```

Great, now you have a basic implementation of the NavigationProgress component in your Remix application! You can play with the component props and reacting to the different transition types to improve the experience as you see fit.