Animations

Scroll Progress

new

A hairline that fills as the page or a container scrolls.

How the tokens are layered

The stylesheet has two layers. The palette holds every raw value and nothing else: a ramp of neutrals and the four status ramps, green, amber, blue and red, shared by both themes.

The semantic layer names roles and points them at palette steps. Components reference roles, never steps, so a theme is a list of assignments rather than a second copy of every rule.

Two accents

Primary is the action color and stays neutral. Brand is the identity color, used for focus, selection and checked state. Keeping them apart means a new brand color never repaints every button.

Dark mode

The dark theme re-points the same roles at darker steps. Borders and inputs become translucent white, so they read on any surface without a dedicated dark value per component.

To add a role, add it to the semantic layer in both themes and expose it to Tailwind. Nothing in a component ever needs a hex.

Installation

npx shadcn@latest add @blank/scroll-progress

Usage

import { ScrollProgress } from "@/components/ui/scroll-progress"
<ScrollProgress />

On its own it tracks the page and is pinned to the top of the viewport. Pass container to track a scrollable element instead, and position the bar yourself, for example with sticky top-0 as its first child.

The bar is brand. It only moves when the reader scrolls, so there is nothing to turn off for reduced motion.

Props

PropTypeDefault
containerRefObject<HTMLElement>the page
classNamestring—