Scroll Highlighter

v1.0.1
FreeScroll

A premium typography scroll-highlighter that highlights text word-by-word with solid, wavy, or dotted styles based on page scroll or custom motion values.

Scroll Highlighter

Installation

Step 1. Initialize ProjectOne-time setup

Run once in your project root to configure paths and dependencies:

npx vectorvesper init
Step 2. Add ComponentInstalls source & assets

Downloads and registers the component in your project:

npx vectorvesper add scroll-highlighter
Step 3. Required DependenciesAuto-installed with CLI

If installing manually or managing your package lock:

npm install framer-motion
Packages:framer-motion

Usage

Import

import ScrollHighlighter from "@/components/vv/scroll-highlighter";

Usage

<ScrollHighlighter />
This component respects prefers-reduced-motion and provides a graceful fallback.

Props

A paragraph that highlights itself word by word as it scrolls into view, like someone running a marker across the line. The mark can be a solid block, a hand-drawn wave, or a dotted underline.

<ScrollHighlighter />

The passage and its highlight.

PropTypeDefaultDescription
text*stringThe passage. Required.
variant"solid" | "wavy" | "dotted""solid"What the mark looks like. It also sets the three values below.
highlightColorstringper variantColour of the mark. Solid uses a translucent yellow; wavy and dotted use a solid one, since a thin line needs the weight.
highlightHeightnumber0.55 solid · 0.28 wavy · 0.18 dottedThickness of the mark, as a fraction of the line height.
highlightYnumber0.38 solid · 0.68 wavy · 0.82 dottedWhere the mark sits vertically, 0 at the top of the line and 1 at the bottom. Solid sits across the text; the other two sit under it.
highlightOpacitynumber1.0Opacity of the mark.
gradientColors[string, string]Runs the mark as a gradient between two colours instead of a flat fill.
overlapnumber1.5How far the mark extends past each word, so consecutive words join into a continuous stroke.
hoverGlowbooleantrueLifts a word when the cursor is over it.
textColorstring"#646973"Colour of words not yet reached.
activeTextColorstring"#FFFFFF"Colour of words the highlight has passed.
baseFontOpacitynumber1.0Opacity of words not yet reached. Lower it to fade them back further.
activeFont"default" | "dramatic""default"Whether highlighted words switch to a second face as they activate. `dramatic` is the built-in serif italic.
baseFontClassstring""Class applied to words not yet reached.
dramaticFontClassstring"font-cormorant italic"Class applied to activated words when activeFont is `dramatic`. The default names a font the component does not load — point it at one of yours.
stickybooleanfalsePins the passage while the highlight runs, instead of letting it scroll past.
fullscreenbooleanfalseGives the passage the full viewport height.
scrollSpeednumber0.001How quickly the highlight advances relative to the scroll.
offset[string, string]["start 0.85", "end 0.35"]Where in the viewport the highlight starts and finishes. The defaults begin just as the passage enters and end before it leaves.
customProgressMotionValue<number>Drives the highlight from your own value instead of the scroll position — for a timeline, or a shared scroll container.
smoothbooleantrueEases the highlight rather than tracking the scrollbar exactly.
physicsProfilePhysicsProfileName"gentle"Named spring for that easing. Four are provided.
springConfigSpringConfigfrom the profileYour own damping, stiffness and mass, overriding the profile entirely.
classNamestring""Applied to the wrapper.

Presets

PresetDescriptionKey Overrides
"gentle"The default. Settles without overshoot.
damping=25stiffness=140mass=0.6
"buttery"Slower and heavier, with a long glide.
damping=35stiffness=100mass=1.0
"snappy"Quick and tight.
damping=22stiffness=200mass=0.5
"bouncy"Overshoots and settles back.
damping=12stiffness=90mass=0.8

Examples

Basic passage
import ScrollHighlighter from "@/components/vv/scroll-highlighter/ScrollHighlighter";

<ScrollHighlighter text="We build interfaces that feel like objects rather than pages." />
A hand-drawn underline, pinned
<ScrollHighlighter
  text="Every detail earns its place."
  variant="wavy"
  highlightColor="#7EACB5"
  sticky
  fullscreen
  physicsProfile="buttery"
/>
Driven by your own progress
const progress = useMotionValue(0);

<ScrollHighlighter text={copy} customProgress={progress} />
The highlight is scroll-driven, so it only moves when the visitor scrolls. Set smooth={false} when reduced motion is preferred and it tracks the scrollbar exactly, with no easing of its own.
The dramatic font class names Cormorant, which the component does not load. Either load it or point dramaticFontClass at a face you already have.
Every word is measured and animated separately, so cost scales with length. A long essay in one instance is heavier than several short passages.

Source

/**
 * Scroll Highlighter — Vector Vesper
 * https://vectorvesper.dev/components
 *
 * Copyright (c) 2026 Vector Vesper
 * Released under the MIT License. This notice must be retained in copies and
 * substantial portions of the file. https://vectorvesper.dev/license
 */
export { default } from "./ScrollHighlighter";
export * from "./ScrollHighlighter";
View on GitHubReport an issue