Marble UI
← Components

Navigation Progress

Preview: Default

Thin progress bar pinned to the top of the page (or a positioned container) during route changes.

Import

import { NavigationProgress } from '@marbleui/ui'
import { useNavigationProgress } from '@marbleui/ui'

Props

<NavigationProgress>

PropTypeDefaultDescription
value *requirednumber | null—
classNamestring—
fixedboolean—

Hooks

useNavigationProgress(): { value: number | null; start: () => void; done: () => void; }

Imperative controller for the top loading bar: start() trickles toward 90%, done() completes and fades out.

Usage notes

Thin bar across the top of the page (or a container) while a route change loads, driven by useNavigationProgress(). For progress you can actually measure use ProgressBar.

const progress = useNavigationProgress()
async function go(path: string) { progress.start(); await loadRoute(path); progress.done() }
<NavigationProgress value={progress.value} fixed />
  • The progress is simulated: start() jumps to 8% and creeps toward 90%, done() fills to 100% and hides the bar 400 ms later. It isn’t tied to any router, so call both from your navigation events.
  • value={null} hides the bar. fixed pins it to the top of the viewport; otherwise it’s absolute, so the parent needs relative.
  • It’s a role="progressbar" labelled “Page loading”, hidden from assistive tech while idle.
  • Calling start() soon after done() cancels the pending hide, so back-to-back navigations show the bar.
Example source · show
import { useState } from 'react'
import { Button } from '../button'
import { NavigationProgress, useNavigationProgress } from './navigation-progress'

function Demo() {
  const p = useNavigationProgress()
  const [page, setPage] = useState('Overview')
  const go = (to: string) => { p.start(); setTimeout(() => { setPage(to); p.done() }, 1400) }
  return (
    <div className="relative w-96 overflow-hidden rounded-xl border border-border bg-surface">
      <NavigationProgress value={p.value} />
      <nav className="flex gap-1 border-b border-border p-2">{['Overview', 'Issues', 'Settings'].map((l) => <Button key={l} size="sm" variant={l === page ? 'soft' : 'ghost'} onPress={() => go(l)}>{l}</Button>)}</nav>
      <div className="grid h-32 place-items-center text-sm text-fg-muted">{page}</div>
    </div>
  )
}
export const styles = { Default: Demo }

Source: packages/ui/src/navigation-progress/navigation-progress.tsx

Catalog

Category
navigation
Priority
Extra
Primitive
composed
React Aria
ProgressBar
Base UI
Progress