GitHub

Page Progress

A thin top-of-page progress indicator for route transitions and optimistic navigation feedback. It pairs with the useProgressBar hook to animate route changes without blocking content.

Dark ModeAnimatedPortal

Install

$npx react-principles add page-progress

This demo wires the component to useProgressBar so you can replay a route transition and observe the bar animating at the top of the viewport.

Simulate a route transition

Trigger the hook and watch the top edge of the viewport for the animated progress bar.

Visible

No

Progress

0%

Runs

0

02

Code Snippet

src/ui/PageProgress.tsx
import { useState } from "react";
import { PageProgress } from "@/ui/PageProgress";
import { useProgressBar } from "@/shared/hooks/useProgressBar";

export function RouteFeedback() {
  const [navigationKey, setNavigationKey] = useState("initial");
  const { progress, visible } = useProgressBar(navigationKey);

  return (
    <>
      <button onClick={() => setNavigationKey(`nav-${Date.now()}`)}>
        Simulate navigation
      </button>
      <PageProgress progress={progress} visible={visible} />
    </>
  );
}
03

Copy-Paste (Single File)

PageProgress.tsx
import { cn } from "@/lib/utils";

export interface PageProgressProps {
  progress: number;
  visible: boolean;
}

export function PageProgress({ progress, visible }: PageProgressProps) {
  return (
    <div
      role="progressbar"
      aria-valuemin={0}
      aria-valuemax={100}
      aria-valuenow={progress}
      aria-hidden="true"
      className={cn(
        "pointer-events-none fixed left-0 top-0 z-200 h-0.5 bg-primary",
        "shadow-[0_0_8px_1px_rgba(70,40,241,0.7)]",
        "transition-opacity duration-300",
        visible ? "opacity-100" : "opacity-0"
      )}
      style={{
        width: `${progress}%`,
        transition: `width ${progress === 0 ? "0ms" : progress === 100 ? "150ms" : "350ms"} ease-out, opacity 300ms`,
      }}
    />
  );
}
04

Props

PropTypeDefaultDescription
progressnumberCurrent completion percentage from 0 to 100.
visiblebooleanControls the fade-in and fade-out visibility state.
react-principles