Skip to main content
Clever Ops

Progress Thread

An article wrapper that draws a hairline thread down the content's left edge, filling with primary as you read and ticking a milestone dot at every h2, a reading instrument.

Preview & code

Loading Progress Thread preview

Installation

pnpm dlx shadcn@latest add @cleverui/scroll-progress-thread

Requires the @cleverui registry in your components.json, a one-off, two-line setup.

Usage

tsx
import { ScrollProgressThread } from '@/components/ui/scroll-progress-thread'
Exampletsx
import { ScrollProgressThread } from '@/components/ui/scroll-progress-thread'

export default function ScrollProgressThreadDemo() {
  return (
    <div className="py-12 sm:py-16">
      <ScrollProgressThread showLabels>
        <article className="space-y-10">
          <header className="space-y-4">
            <p className="font-mono text-[11px] uppercase tracking-[0.2em] text-muted-foreground sm:text-xs">
              Field notes · issue 12
            </p>
            <h1 className="text-3xl font-semibold tracking-tight text-balance text-foreground sm:text-4xl">
              How Meridian Labs cut close from nine days to three
            </h1>
            <p className="text-base leading-relaxed text-muted-foreground sm:text-lg">
              A walkthrough of the ledger rebuild that replaced weekend
              firefighting with a nightly exception board, written for
              controllers who still open the general ledger by hand.
            </p>
          </header>

          <section className="space-y-4">
            <h2 className="text-xl font-semibold tracking-tight text-foreground sm:text-2xl">
              The bottleneck was not the ERP
            </h2>
            <p className="text-sm leading-relaxed text-muted-foreground sm:text-base">
              Meridian ran NetSuite cleanly. What failed was the gap between
              warehouse receipts and AP: 2,400 lines a month arrived as PDFs,
              emails, and portal exports. Analysts spent four hours a day
              re-keying amounts that already existed somewhere in the stack.
            </p>
            <p className="text-sm leading-relaxed text-muted-foreground sm:text-base">
              We mapped every handoff for one full close. Eighteen of
              twenty-two delays sat outside the ERP, in shared drives, Slack
              threads, and a spreadsheet named “FINAL_v7_use_this.”
            </p>
          </section>

          <section className="space-y-4">
            <h2 className="text-xl font-semibold tracking-tight text-foreground sm:text-2xl">
              Instrument the reading path first
            </h2>
            <p className="text-sm leading-relaxed text-muted-foreground sm:text-base">
              Before any automation, the team installed a single exception
              board. Every unmatched line carried a status, owner, and age.
              Reading progress on the board became the stand-up, not a
              status meeting about status meetings.
            </p>
            <p className="text-sm leading-relaxed text-muted-foreground sm:text-base">
              Milestone dots in this demo mirror that idea: the thread
              measures real headings in the document, not an arbitrary
              scroll percentage. You always know where you are in the
              argument.
            </p>
          </section>

          <section className="space-y-4">
            <h2 className="text-xl font-semibold tracking-tight text-foreground sm:text-2xl">
              What shipped in thirty days
            </h2>
            <p className="text-sm leading-relaxed text-muted-foreground sm:text-base">
              Phase one extracted invoice fields against Meridian’s chart of
              accounts, not a generic template. Phase two wired dual-approval
              thresholds into the match engine. Phase three sealed nightly
              audit packs with source hashes for the external auditors.
            </p>
            <p className="text-sm leading-relaxed text-muted-foreground sm:text-base">
              Close dropped from nine calendar days to three. Exception age
              fell from 41 hours median to under six. The controller’s only
              remaining complaint: the board is almost too quiet.
            </p>
          </section>

          <section className="space-y-4">
            <h2 className="text-xl font-semibold tracking-tight text-foreground sm:text-2xl">
              What we would change next time
            </h2>
            <p className="text-sm leading-relaxed text-muted-foreground sm:text-base">
              Start with the reading instrument. Automation without a shared
              view of “what is still open” just moves the fire. Build the
              thread first, then fill it.
            </p>
          </section>
        </article>
      </ScrollProgressThread>
    </div>
  )
}

API reference

ScrollProgressThread accepts the following props.

PropTypeDefaultDescription
children*React.ReactNodethe long-form article content the thread measures
headingSelectorstring'h2'CSS selector for milestone headings; dots positioned at each match after mount
showLabelsbooleantruerender mono heading labels beside milestone dots on lg screens

…plus everything from React.HTMLAttributes<HTMLDivElement>: className, event handlers, aria attributes and the rest pass straight through.

Frequently asked questions

How do I install the Progress Thread component?

Register the @cleverui registry in your components.json ("@cleverui": "https://cleverops.com.au/r/{name}.json"), then run `npx shadcn@latest add @cleverui/scroll-progress-thread`. The shadcn CLI copies the source into your project, you own the code from that point. You can also copy the source directly from this page.

What dependencies does Progress Thread require?

Progress Thread uses motion on top of React and Tailwind CSS. You don't need to install it manually, the shadcn CLI resolves and installs npm dependencies automatically when you add the component.

Can I theme Progress Thread to match my brand?

Yes. The component is styled entirely with Tailwind utilities over standard design tokens (primary, background, muted, border), so it inherits your existing shadcn/ui theme automatically. Change your CSS variables and the component follows, no source edits needed for palette, radius, or fonts.

Want this built for you?

CleverUI is built by the Clever Ops web team. If you'd rather ship a hand-coded, fast, custom website than assemble one, we build them for Australian businesses every week.

Explore web development services