DEV Community

Cover image for Using Mantine NavigationProgress with Remix
donocode
donocode

Posted on

Using Mantine NavigationProgress with Remix

Today we are going to learn how to implement the NavigationProgress component from Mantine.dev 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.

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

Remix useTransition hook

Remix provides a 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.

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} />;
};
Enter fullscreen mode Exit fullscreen mode

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.

    <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>
Enter fullscreen mode Exit fullscreen mode

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.

Top comments (0)