NProgress Integration Guide
Learn how to integrate NProgress navigation feedback in ProductReady
NProgress Integration Guide
Overview
NProgress is integrated throughout the ProductReady application to provide visual feedback during page navigations. The implementation is designed to work seamlessly with Next.js 13+ App Router.
Architecture
Components
-
NProgressProvider (
src/components/nprogress/nprogress-provider.tsx)- Client component that tracks route changes
- Uses
usePathname()anduseSearchParams()hooks - Automatically shows/hides progress bar on navigation
- Configured once on mount
-
NProgressLink (
src/components/nprogress/nprogress-link.tsx)- Wrapper around
next/linkthat starts progress on click - Respects
onClickevent handlers - Honors
preventDefault()calls
- Wrapper around
-
useNProgressRouter (
src/components/nprogress/nprogress-link.tsx)- Hook that wraps Next.js
useRouterwith progress indication - Provides:
push,replace,back,forward,refresh - Each navigation method starts NProgress automatically
- Hook that wraps Next.js
-
configureNProgress (
src/components/nprogress/nprogress-config.ts)- Centralized configuration
- Called once when NProgressProvider mounts
Integration Points
Root Layout (layout.tsx)
└─ Global CSS (includes nprogress.css)
[lang] Layout (for marketing pages)
└─ LangLayoutClient (client component)
└─ NProgressProvider
└─ RootProvider (Fumadocs)
└─ Children (marketing pages)
(dashboard) Layout (for dashboard pages)
└─ ThemeProvider
└─ TRPCProvider
└─ NProgressProvider
└─ Children (dashboard pages)Usage
Automatic (No Code Changes)
Most navigation is handled automatically:
- All internal
<a>link clicks are intercepted globally - no special components needed - Existing
next/linkcomponents work automatically - Fumadocs sidebar, breadcrumbs, and navigation links work automatically
- Browser back/forward buttons trigger progress
- URL changes from any source show progress
The NProgressProvider uses a global click listener that intercepts all internal link clicks, so you don't need to use special Link components like NProgressLink or WebLink for NProgress to work.
Manual Control (Advanced)
Using NProgressLink
import { NProgressLink } from '~/components/nprogress';
// Replace next/link with NProgressLink
<NProgressLink href="/dashboard" className="...">
Go to Dashboard
</NProgressLink>Using useNProgressRouter
import { useNProgressRouter } from '~/components/nprogress';
function MyComponent() {
const router = useNProgressRouter();
const handleClick = () => {
// Progress bar starts automatically
router.push('/settings');
};
return <button onClick={handleClick}>Settings</button>;
}Direct NProgress API
import NProgress from 'nprogress';
// Manual start
NProgress.start();
// Manual complete
NProgress.done();
// Set specific percentage (0 to 1)
NProgress.set(0.4);
// Increment
NProgress.inc();Configuration
Global Settings
Edit src/components/nprogress/nprogress-config.ts:
NProgress.configure({
showSpinner: true, // Show spinner in top-right
speed: 400, // Animation speed (ms)
minimum: 0.08, // Starting percentage
easing: "ease", // CSS easing function
trickle: true, // Auto-increment
trickleSpeed: 200, // Trickle interval (ms)
});Styling
Edit src/app/global.css under the "NProgress custom styling" section:
/* Progress bar color */
#nprogress .bar {
background: oklch(0.646 0.222 41.116); /* Light mode */
}
.dark #nprogress .bar {
background: oklch(0.769 0.188 70.08); /* Dark mode */
}
/* Bar height */
#nprogress .bar {
height: 3px; /* Adjust as needed */
}
/* Spinner color */
#nprogress .spinner-icon {
border-top-color: oklch(0.646 0.222 41.116);
border-left-color: oklch(0.646 0.222 41.116);
}Best Practices
DO
✅ Use automatic integration (no code changes needed)
✅ Keep progress bar visible but subtle
✅ Test on slow connections (Network Throttling in DevTools)
✅ Ensure contrast in both light and dark modes
✅ Call NProgress.done() when programmatically controlling
DON'T
❌ Start progress without finishing it (causes stuck progress bar)
❌ Use NProgress for non-navigation loading (use Suspense instead)
❌ Call NProgress.start() twice without done() in between
❌ Override styles without maintaining theme consistency
Debugging
Progress Bar Doesn't Appear
- Check browser console for errors
- Verify NProgressProvider is in the component tree
- Ensure CSS is imported (
@import "nprogress/nprogress.css") - Check z-index conflicts (NProgress uses z-index: 9999)
Progress Bar Gets Stuck
// Force complete the progress
NProgress.done(true);
// Or in console:
window.NProgress.done(true);Multiple Progress Bars
This happens when multiple NProgressProviders are mounted. Ensure only one provider exists in the component tree (at layout level).
Performance
- Bundle Size: ~2KB gzipped (nprogress library)
- Runtime Overhead: Negligible (passive event listeners)
- Animation Cost: Uses CSS transforms (GPU accelerated)
Browser Support
NProgress works in all modern browsers:
- Chrome/Edge (latest)
- Firefox (latest)
- Safari (latest)
- Mobile browsers (iOS Safari, Chrome Mobile)
Accessibility
- Progress bar is visual only (no ARIA announcements)
- Does not interfere with screen readers
- Does not trap keyboard focus
- Color contrast meets WCAG AA standards in both themes
Migration from Pages Router
If migrating from Next.js Pages Router:
- Remove old router event listeners (
router.events.on) - Remove manual
NProgress.start()/NProgress.done()calls - Add
NProgressProviderto your App Router layout - Navigation will work automatically