feat(ReadingProgressBar): scroll-progress bar for long-form pages - #396
feat(ReadingProgressBar): scroll-progress bar for long-form pages#396ebellamy-bh wants to merge 2 commits into
Conversation
Ported from the Enterprise Health frontdoor: a thin aria-hidden bar pinned to the viewport top tracking document scroll. Generalized to token colors (bg-primary-500 default, barClassName override) with an rAF-coalesced scroll handler.
There was a problem hiding this comment.
Pull request overview
Adds a new ReadingProgressBar component to the UI library for long-form pages: a thin, fixed bar at the top of the viewport that fills based on document scroll progress. This complements existing long-form wayfinding components (e.g., TableOfContents, SectionSpyNav).
Changes:
- Introduces
ReadingProgressBarReact component with scroll/resize tracking and class overrides. - Adds unit tests covering initial state, scroll tracking, clamping/unscrollable docs, and
aria-hidden+ custom bar class. - Adds Storybook stories and wires the component into the package exports/build entrypoints.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| tsup.config.ts | Adds ReadingProgressBar entry to the build export map. |
| src/index.ts | Re-exports ReadingProgressBar from the package root. |
| src/components/ReadingProgressBar/ReadingProgressBar.tsx | Implements the fixed, scroll-tracking progress bar. |
| src/components/ReadingProgressBar/ReadingProgressBar.test.tsx | Adds unit tests for scroll progress behavior and props. |
| src/components/ReadingProgressBar/ReadingProgressBar.stories.tsx | Adds Storybook coverage for default and customized styling. |
| src/components/ReadingProgressBar/index.ts | Component barrel export for local imports and root export. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Deploying ui with
|
| Latest commit: |
8550366
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://8b7b5efb.ui-6d0.pages.dev |
| Branch Preview URL: | https://feat-reading-progress-bar.ui-6d0.pages.dev |
…o 0, click-through bar - Progress is clamped to 0–100 so iOS rubber-band overscroll (negative scrollTop) cannot render a negative-width fill - The fixed overlay gets pointer-events-none so it never intercepts clicks on content beneath it
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 6 out of 6 changed files in this pull request and generated no new comments.
Suppressed comments (3)
Previously missed (3) — in code that hasn't changed since the last review.
src/components/ReadingProgressBar/ReadingProgressBar.tsx:9
ReadingProgressBarPropsextendsReact.HTMLAttributes<HTMLDivElement>, which includeschildren, but this component always renders its own internal children and will ignore any consumer-provided children. Consider omittingchildrenfrom the props type to avoid a misleading API (matches patterns likeDashboardWidgetTablePropsinsrc/components/DashboardWidget/DashboardWidget.tsx:296).
export interface ReadingProgressBarProps extends React.HTMLAttributes<HTMLDivElement> {
/** Class for the filled bar (default `bg-primary-500`). */
barClassName?: string;
}
src/components/ReadingProgressBar/ReadingProgressBar.tsx:64
- Because
{...props}is spread afteraria-hiddenon the outer<div>, consumers can overridearia-hidden(e.g.aria-hidden={false}) even though the component is documented as “purely decorative”. If decorative is intended to be enforced, spreadpropsfirst soaria-hidden="true"cannot be overridden.
<div
ref={ref}
aria-hidden="true"
className={cn(
'pointer-events-none fixed inset-x-0 top-0 z-50 h-1 bg-transparent',
className
)}
{...props}
>
src/components/ReadingProgressBar/ReadingProgressBar.tsx:75
- Most
forwardRefcomponents in this codebase set adisplayNamefor clearer React DevTools output (e.g.Button.displayNameinsrc/components/Button/Button.tsx:186,Input.displayNameinsrc/components/Input/Input.tsx:150). Adding one here would improve debugging ergonomics.
});
Ports the Enterprise Health frontdoor's reading-progress bar — the thin bar pinned to the viewport top that fills as the reader scrolls a long-form page.
What it does
aria-hidden); token-colored withbg-primary-500default andbarClassName/classNameoverrides for color and thicknessTableOfContentsandSectionSpyNav(feat(SectionSpyNav): sticky in-page section nav with sliding underline #392) as the third piece of long-form wayfindingScreenshots
Mid-article, ~55% read:
Provenance
Port of
enterprise-health-frontdoor/components/ui/ReadingProgressBar.tsx, retokened from the EH gilt to the primary scale.Testing
typecheck/lint/format/rtl:scanclean; combined batch suite 622/622