Skip to content
Redpanda UI
Esc
↑↓navigate↵open⌘Jpreview
Made by imskyleen
Edit on GitHub

Scroll Progress

A scroll progress component that displays the progress of the scroll.

Installation

bash
npx shadcn@latest add @redpanda/scroll-progress
bash
pnpm dlx shadcn@latest add @redpanda/scroll-progress
bash
yarn dlx shadcn@latest add @redpanda/scroll-progress
bash
bunx shadcn@latest add @redpanda/scroll-progress
bash
nubx shadcn@latest add @redpanda/scroll-progress
bash
aube dlx shadcn@latest add @redpanda/scroll-progress

Vertical orientation

Pass orientation="vertical" to pin the progress bar to the left edge of a positioned ancestor (scaleY instead of scaleX). Useful for reading-progress indicators inside sidebars or detail panels.

When to use

Scroll Progress provides visual feedback about reading progress through content. Use this decision tree to determine when it’s appropriate:

Motion features

ScrollProgress includes its synchronous Motion features; no application-level LazyMotion provider is required. The progressProps HTMLMotionProps contract retains drag and layout support. Its scroll-driven scale composes with consumer Motion transforms and inherits an enclosing MotionConfig.

Usage

Global Page Scroll Progress

Track the scroll progress of the entire page:

tsx
import { ScrollProgress } from '@/components/redpanda-ui/scroll-progress';
// Add to your main layout or pagefunction App() {  return (    <>      <ScrollProgress />      <main>        {/* Your page content */}        <article className="max-w-4xl mx-auto px-6 py-12">          <h1>Long Article Title</h1>          <p>Very long content that will require scrolling...</p>          {/* More content */}        </article>      </main>    </>  );}

Local Container Scroll Progress

Track scroll progress within a specific scrollable container:

tsx
<ScrollProgress className="h-[400px] w-full border rounded-lg p-6">  <div className="space-y-6">    <h2>Scrollable Content Section</h2>    <p>This content will scroll within the container...</p>    {Array.from({ length: 20 }).map((_, i) => (      <div key={i} className="p-4 border rounded">        <h3>Section {i + 1}</h3>        <p>Content for section {i + 1} goes here. This demonstrates the local scroll progress tracking.</p>      </div>    ))}  </div></ScrollProgress>

Custom Styled Progress Bar

Customize the appearance of the progress bar:

tsx
<ScrollProgress  progressProps={{    className: 'fixed z-50 top-0 inset-x-0 h-2 bg-gradient-to-r from-primary to-brand origin-left',    style: {      boxShadow: '0 0 10px rgba(59, 130, 246, 0.5)',    },  }}>  <div className="h-[200vh] p-6">    <h1>Custom Styled Progress</h1>    <p>Long content with a custom gradient progress bar...</p>  </div></ScrollProgress>

Reading Progress for Articles

Ideal for blog posts and articles:

tsx
function BlogPost() {  return (    <>      <ScrollProgress        progressProps={{          className: 'fixed z-50 top-0 inset-x-0 h-1 bg-primary origin-left transition-opacity duration-300',        }}      />      <article className="max-w-2xl mx-auto px-4 py-16">        <header className="mb-12">          <h1 className="text-4xl font-bold mb-4">How to Build Better UIs</h1>          <p className="text-subtle">A comprehensive guide...</p>        </header>
        {/* Long article content */}        <p className="text-body-lg">Your article content goes here...</p>      </article>    </>  );}

Multiple Progress Indicators

Use different progress bars for different sections:

tsx
<div className="space-y-8">  <ScrollProgress    className="h-[300px] border rounded-lg p-4"    progressProps={{      className: 'absolute top-0 inset-x-0 h-1 bg-informative origin-left',    }}  >    <h3>Section 1</h3>    <div className="space-y-4">{/* Content for section 1 */}</div>  </ScrollProgress>
  <ScrollProgress    className="h-[300px] border rounded-lg p-4"    progressProps={{      className: 'absolute top-0 inset-x-0 h-1 bg-success origin-left',    }}  >    <h3>Section 2</h3>    <div className="space-y-4">{/* Content for section 2 */}</div>  </ScrollProgress></div>

Anatomy

The Scroll Progress component uses Motion/Framer Motion to create smooth scroll-tracking animations:

plaintext
<ScrollProgress> Component├── <motion.div> Progress Bar│   ├── Fixed Positioning (global) | Absolute (local)│   ├── scaleX Animation - horizontal progress indicator│   ├── useSpring Hook - smooth animation transitions│   │   ├── stiffness: 250 - animation responsiveness│   │   ├── damping: 40 - bounce control│   │   └── bounce: 0 - no overshoot│   └── Visual Styling│       ├── height: h-1 (4px) default│       ├── background: bg-primary│       ├── origin: origin-left (scales from left)│       └── z-index: z-50 (above other content)├── Scroll Detection│   ├── useScroll Hook - tracks scroll position│   ├── scrollYProgress - normalized 0-1 value│   └── Container targeting (global vs local)└── Content Container (local mode only)    ├── Scrollable wrapper - overflow-y-auto    ├── Height management - h-full default    └── Content rendering area
Animation Flow:├── Scroll Event → useScroll → scrollYProgress (0-1)├── useSpring → smooth value transformation├── scaleX style → visual progress bar width└── Real-time updates as user scrolls
Positioning Modes:├── Global Mode (no children)│   ├── Tracks document scroll│   ├── Fixed positioning│   └── Full viewport width└── Local Mode (with children)    ├── Tracks container scroll    ├── Absolute/relative positioning    └── Container-specific width

Key Features:

  • Smooth Animation: Spring-based physics for natural motion
  • Dual Mode: Global page tracking or local container tracking
  • Customizable Styling: Full control over appearance and positioning
  • Performance Optimized: Uses requestAnimationFrame for smooth updates
  • Responsive: Adapts to container width automatically
  • Zero Configuration: Works out of the box with sensible defaults

Props

PropType
progressProps?HTMLMotionProps<"div">

The props for the progress element

TypeHTMLMotionProps<"div">
className?string

The class name for the scroll progress

Typestring
children?React.ReactNode

The children for the scroll progress (if not provided, the progress will be global)

TypeReact.ReactNode

Credits

Recent changes

  • patchv1.2.0Pin shipped dependency floors to the version we develop against. Registry items now declare ranges like `^5.1.9` (the actual installed version) instead of collapsing to `^5.0.0`, so consumers start on the known-tested baseline while caret semantics still allow any compatible release within the same major.#133
  • minorv1.1.0Theme docs refresh, readability pass on semantic foregrounds, and consumer-facing Base UI regression fixes.#121
  • minorv1.0.0Post-Base-UI polish. Public API unchanged.#116
  • majorv1.0.0Migrate every Radix-based primitive to `@base-ui/react@^1.4.0` (Base UI).#114
  • minorv0.3.0Add theme-provider component to the registry with documentation and tests. Includes playground type improvements (export RegistryItem, remove as-const boilerplate) and docs site dark mode border color fix.#109
See full history →

Last updated on

Was this page helpful?