Scroll progress indicator that tracks position and modulates bar thickness and luminance intensity based on scroll velocity in horizontal or vertical orientation.
Preview
Customize
4 props64
1.8
Installation
Copies the component source and its CSS Module into your project.
npx motionfoundry add scroll-velocity-progressWrites components/ui/scroll-velocity-progress.tsx and components/styles/scroll-velocity-progress.module.css.
Usage
Updates live as you change the controls — only props that differ from the defaults are included.
example.tsx
1import { ScrollVelocityProgress } from "@motionfoundry/ui";2 3export function Example() {4 return (5 <ScrollVelocityProgress />6 );7}Props
Accessibility
Renders role='progressbar' with aria-valuemin={0}, aria-valuemax={100}, and aria-valuenow={progress} and disables velocity thickness modulation under prefers-reduced-motion.
Toggle prefers-reduced-motion in your OS or browser devtools (Rendering → Emulate CSS media feature) to verify the reduced-motion state.
Source
components/ui/scroll-velocity-progress.tsx
1"use client";2 3import * as React from "react";4import styles from "../styles/scroll-velocity-progress.module.css";5 6export interface ScrollVelocityProgressProps {7 /** Scroll completion percentage (0 to 100) */8 progress?: number;9 /** Velocity multiplier (0 to 4) */10 velocity?: number;11 /** Orientation mode */12 orientation?: "horizontal" | "vertical";13 /** Bar accent color */14 accentColor?: string;15 /** Optional className */16 className?: string;17}18 19export function ScrollVelocityProgress({20 progress = 64,21 velocity = 1.8,22 orientation = "horizontal",23 accentColor = "#38bdf8",24 className = "",25}: ScrollVelocityProgressProps) {26 const clampedProgress = Math.min(100, Math.max(0, progress));27 const thickness = Math.min(12, 4 + velocity * 1.6);28 29 return (30 <div className={`${styles.card} ${className}`.trim()}>31 <div className={styles.metaRow}>32 <span className={styles.label}>SCROLL VELOCITY TELEMETRY</span>33 <span className={styles.readout}>34 {clampedProgress}% • {velocity.toFixed(1)}x vel35 </span>36 </div>37 38 <div39 role="progressbar"40 aria-label="Page scroll progress"41 aria-valuemin={0}42 aria-valuemax={100}43 aria-valuenow={Math.round(clampedProgress)}44 className={orientation === "vertical" ? styles.trackVertical : styles.trackHorizontal}45 style={46 orientation === "vertical"47 ? { width: `${thickness}px` }48 : { height: `${thickness}px` }49 }50 >51 <div52 className={styles.fill}53 style={54 orientation === "vertical"55 ? {56 height: `${clampedProgress}%`,57 width: "100%",58 backgroundColor: accentColor,59 boxShadow: `0 0 ${Math.round(velocity * 6)}px ${accentColor}`,60 }61 : {62 width: `${clampedProgress}%`,63 height: "100%",64 backgroundColor: accentColor,65 boxShadow: `0 0 ${Math.round(velocity * 6)}px ${accentColor}`,66 }67 }68 />69 </div>70 </div>71 );72}