I tried @bprogress/react which allows for easy integration of progress bars in React apps

I tried @bprogress/react which allows for easy integration of progress bars in React apps

Introducing a router-independent progress bar library @bprogress/react. With a simple design that only requires calling start() / stop() with the useProgress hook, it offers rich customization options including color, height, easing and more.
2026.04.02

This page has been translated by machine translation. View original

Web apps often need to show a "I'm loading something, please wait" message during page transitions or data fetching, right?

@bprogress/react allows you to easily integrate progress bars into React apps without depending on a specific router.
After trying it out, I found it had more flexibility than I expected, so I'd like to introduce it.

First, try out the StackBlitz demo.
Click Fetch data and you'll see a bar run across the top for 2 seconds, giving the impression of loading.

What is @bprogress/react?

@bprogress/react is a TypeScript-based progress bar library built on NProgress.

https://bprogress.vercel.app/docs/

What makes it distinctive is that it's router-independent.
While libraries like next-nprogress-bar for Next.js automatically hook into router events, @bprogress/react is designed for you to manually call start() / stop() using the useProgress hook. There's also a useAnchorProgress hook for those who want automatic behavior, but the library is fundamentally built for manual control.

There are dedicated packages for Next.js, Remix, and Vue in addition to React.

Installation

npm install @bprogress/react
# or
pnpm add @bprogress/react

Basic Usage

1. Wrap your app with ProgressProvider

Place ProgressProvider at the root of your app. Setting disableStyle disables the default styles, allowing you to fully control custom styles with the css() function (discussed later).

src/main.tsx
import { ProgressProvider } from '@bprogress/react';
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App.tsx';

ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
  <React.StrictMode>
    <ProgressProvider disableStyle>
      <App />
    </ProgressProvider>
  </React.StrictMode>
);

2. Control the bar with the useProgress hook

Control the bar with start() / stop() / pause() / resume() returned by the useProgress hook.

src/App.tsx
import { useProgress } from '@bprogress/react';

function App() {
  const { start, stop, pause, resume } = useProgress();

  return (
    <div>
      <button onClick={() => start()}>start()</button>
      <button onClick={() => stop()}>stop()</button>
      <button onClick={() => pause()}>pause()</button>
      <button onClick={() => resume()}>resume()</button>
    </div>
  );
}

It's very simple. When combining with API fetching, it looks like this:

const { start, stop } = useProgress();

const handleFetch = async () => {
  start();
  await fetchData();
  stop();
};

Features in the Demo

The demo I created allows you to interactively toggle the following options:

Item Description
Basic controls Manually call start() / stop() / pause() / resume()
Simulated fetch Simulate API fetching with start() → 2-second wait → stop()
Color Select bar color from Blue / Green / Pink / Orange
Height Select bar thickness from 2px / 3px / 4px / 6px
Speed Select animation speed from Slow / Normal / Fast
Easing Animation transition function (linear / ease / ease-in-out / cubic-bezier)
Spinner Toggle spinner visibility and position (4 corners)
Direction Direction the bar extends (LTR(Left To Right) / RTL(Right To Left))
Trickle Toggle the "trickle" feature that automatically advances the bar and its speed

Customization Methods

Change options dynamically with setOptions()

Use setOptions() returned by useProgress to change options at runtime.

const { setOptions } = useProgress();

// Change animation speed
setOptions({ speed: 800 });

// Change easing
setOptions({ easing: "cubic-bezier(0.34, 1.56, 0.64, 1)" });

// Show spinner
setOptions({ showSpinner: true });

// Switch to RTL mode
setOptions({ direction: "rtl" });

// Disable trickle (automatic progress)
setOptions({ trickle: false });

Change styles dynamically with css() function

The css() function from @bprogress/core generates a CSS string with color, height, and spinner position settings. By injecting this into a <style> tag, you can change all styles at once.

import { css } from "@bprogress/core";
import type { SpinnerPosition } from "@bprogress/react";

function applyProgressCss(
  color: string,
  height: string,
  spinnerPosition: SpinnerPosition,
) {
  const id = "bprogress-custom";
  let el = document.getElementById(id) as HTMLStyleElement | null;
  if (!el) {
    el = document.createElement("style");
    el.id = id;
    document.head.appendChild(el);
  }
  el.textContent = css({ color, height, spinnerPosition });
}

// Change color, height, and spinner position at once
applyProgressCss("#22c55e", "4px", "top-right");

Conclusion

I tried @bprogress/react and liked its simple design where you just call the useProgress hook without router dependencies.
It seems useful for lightly indicating loading states.

There are dedicated packages for Next.js and Remix, so consider those if you're using one of those frameworks.

Share this article