npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

use-navigation-progress

v2.1.4

Published

navigation progress hook for Next.js App Router with real progress tracking

Readme

use-navigation-progress

🚀 Production-ready navigation progress hook for Next.js App Router with real progress tracking.

npm version License: MIT TypeScript

Features

  • Real Progress Tracking - No fake simulations, tracks actual navigation steps
  • Production Ready - Performance optimized with RAF, debouncing, and memory leak prevention
  • TypeScript First - Fully typed with excellent IntelliSense support
  • Flexible Configuration - Customizable steps, timeouts, and behaviors
  • Zero Dependencies - Only requires React and Next.js (peer dependencies)

Installation

npm install use-navigation-progress
# or
yarn add use-navigation-progress
# or
pnpm add use-navigation-progress

Quick Start

'use client';
import { useNavigationProgress } from 'use-navigation-progress';

export default function NavigationBar() {
  const { status, progress } = useNavigationProgress();

  if (status !== 'loading') return null;

  return (
    <div className="fixed top-0 left-0 w-full h-1 bg-gray-200 z-50">
      <div
        className="h-full bg-blue-500 transition-all duration-200 ease-out"
        style={{ width: `${progress}%` }}
      />
    </div>
  );
}

Advanced Usage

Custom Steps & Manual Control

const progress = useNavigationProgress({
  enableAutoComplete: false, // Manual control
  timeout: 15000, // 15 second timeout
  steps: [
    { name: "route_change", weight: 20 },
    { name: "auth_check", weight: 15 },
    { name: "data_fetch", weight: 40 },
    { name: "render_complete", weight: 25 }
  ]
});

// In your component
useEffect(() => {
  checkAuth()
    .then(() => progress.markStepComplete('auth_check'))
    .then(() => fetchData())
    .then(() => progress.markStepComplete('data_fetch'))
    .finally(() => progress.finish());
}, []);

Complete Progress Bar Component

'use client';
import { useNavigationProgress } from 'use-navigation-progress';

export function ProgressBar() {
  const { status, progress, duration, error } = useNavigationProgress({
    timeout: 8000,
    debounceMs: 50
  });

  if (status === 'idle') return null;

  return (
    <div className="fixed top-0 left-0 w-full z-50">
      <div className="h-1 bg-gradient-to-r from-blue-500 to-purple-600 origin-left transform transition-transform duration-200 ease-out"
           style={{
             transform: `scaleX(${progress / 100})`,
             opacity: status === 'complete' ? 0 : 1
           }} />

      {error && (
        <div className="bg-red-500 text-white text-sm px-4 py-1">
          Navigation failed: {error}
        </div>
      )}

      {/* Optional: Show duration for debugging */}
      {process.env.NODE_ENV === 'development' && (
        <div className="text-xs text-gray-500 px-2">
          {duration}ms - {progress}%
        </div>
      )}
    </div>
  );
}

API Reference

useNavigationProgress(options?)

Options

| Option | Type | Default | Description | |--------|------|---------|-------------| | timeout | number | 10000 | Timeout in milliseconds before marking navigation as failed | | steps | Array<{name: string, weight: number}> | Default steps | Custom navigation steps with weights | | enableAutoComplete | boolean | true | Automatically complete progress when all steps are done | | debounceMs | number | 100 | Debounce time in milliseconds for progress updates |

Returns

| Property | Type | Description | |----------|------|-------------| | status | 'idle' \| 'loading' \| 'complete' \| 'error' | Current navigation status | | progress | number | Progress percentage (0-100) | | duration | number | Navigation duration in milliseconds | | error | string \| undefined | Error message if status is "error" | | finish | () => void | Manually finish the navigation progress | | markStepComplete | (stepName: string) => void | Mark a specific step as complete | | reset | () => void | Reset progress to idle state |

Default Steps

[
  { name: "route_change", weight: 20 },    // Route change detected
  { name: "component_mount", weight: 30 }, // Component mounted
  { name: "hydration", weight: 25 },       // React hydration complete
  { name: "resources_load", weight: 25 }   // Images and resources loaded
]

Styling Examples

Tailwind CSS

// Simple bar
<div className={`fixed top-0 left-0 h-1 bg-blue-500 z-50 transition-all duration-200 ${
  status === 'loading' ? 'opacity-100' : 'opacity-0'
}`} style={{ width: `${progress}%` }} />

// Gradient bar with glow
<div className="fixed top-0 left-0 w-full h-1 bg-gray-200 z-50">
  <div className="h-full bg-gradient-to-r from-blue-400 via-purple-500 to-pink-500 shadow-lg transition-all duration-300 ease-out"
       style={{ width: `${progress}%` }} />
</div>

CSS Modules

.progressBar {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 3px;
  background: linear-gradient(90deg, #3b82f6, #8b5cf6, #ec4899);
  transform-origin: left;
  transition: transform 200ms ease-out;
  z-index: 9999;
}

.progressBar.complete {
  opacity: 0;
  transition: opacity 300ms ease-out;
}

Best Practices

1. Single Progress Bar Per App

// app/layout.tsx
import { ProgressBar } from '@/components/progress-bar';

export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        <ProgressBar />
        {children}
      </body>
    </html>
  );
}

2. Custom Loading Steps

// For data-heavy pages
const { markStepComplete } = useNavigationProgress({
  steps: [
    { name: "route_change", weight: 15 },
    { name: "auth_validation", weight: 20 },
    { name: "data_prefetch", weight: 35 },
    { name: "component_render", weight: 30 }
  ]
});

3. Error Handling

const { status, error, reset } = useNavigationProgress();

useEffect(() => {
  if (status === 'error') {
    console.error('Navigation failed:', error);
    // Optionally reset after delay
    setTimeout(reset, 3000);
  }
}, [status, error, reset]);

Demos

I've implemented a custom route announcer in slate with this package, you can implement your own top loader, custom route announcer etc with it

License

© MIT