WebberUI

Scroll Text Highlight

Reading highlight that turns text from pale grey to solid foreground, character by character (or word by word), as you scroll.

Loading preview…
npx shadcn@latest add https://webberui.com/r/scroll-text-highlight.json

Playground

Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.

<ScrollTextHighlight />

Installation

npx shadcn@latest add https://webberui.com/r/scroll-text-highlight.json

Or, once registries are configured in components.json, install it as @webberui/scroll-text-highlight.

Usage

Inside a nested scroll container, pass the container's ref to container:

import * as React from "react";
import { ScrollTextHighlight } from "@/components/ui/scroll-text-highlight";

export function Example() {
  const scrollerRef = React.useRef<HTMLDivElement>(null);

  return (
    <div ref={scrollerRef} className="h-[300px] overflow-y-auto">
      <div className="py-40">
        <ScrollTextHighlight
          container={scrollerRef}
          text="Text that lights up character by character as you scroll."
          className="text-xl font-semibold"
        />
      </div>
    </div>
  );
}

When the window itself is the scroll container, container can be omitted:

<ScrollTextHighlight
  by="word"
  text="Scroll to reveal."
  className="text-4xl font-bold"
/>

Props

PropTypeDefaultDescription
textstringThe text to highlight as you scroll
by"char" | "word""char"Smallest unit of highlighting
containerRefObject<HTMLElement>Ref of the nested scroll container; omit to use the window as the scroll container
classNamestringExtra styles (set font size and text color here)

How it works

  • useScroll({ target, container, offset: ["start end", "end start"] }) yields scrollYProgress, the scroll progress of the target text from entering the bottom of the container to leaving the top
  • Each character (or word) is assigned a [start, end] sub-range by index, and useTransform maps progress onto opacity, turning them one by one from pale grey to solid foreground
  • Character mode splits on graphemes, so emoji and combining characters are never broken apart
  • The text inherits currentColor (the foreground color), which naturally reads as light grey while faded; set font size and text color via className

Accessibility

  • The complete text is rendered sr-only for assistive technology, and the per-character animation layer is marked aria-hidden, so nothing is announced twice
  • When the user has "reduce motion" enabled at the system level, the text renders statically in full foreground color

On this page