WebberUI

Scroll Progress Set

滾動進度三合一:頂部進度條、右下圓環與右側章節節點,共用同一個捲動進度。

載入預覽⋯

安裝

npx shadcn@latest add https://webberui.com/r/scroll-progress-set.json

或在 components.json 設定 registries 後,改用 @webberui/scroll-progress-set 安裝。

安裝依賴後,從 registry JSON(/r/scroll-progress-set.jsonfiles[0].content)複製 scroll-progress-set.tsx 原始碼到你的 components/ui/ 目錄:

npm install motion clsx tailwind-merge

使用

ScrollProgressuseScroll 追蹤捲動進度,可切換為三種呈現形式。傳入 container 時會偵測該容器的內部捲動,並把指示器貼齊容器可視區;未傳入時則追蹤整個視窗。

import {
  ScrollProgress,
  type ScrollSection,
} from "@/components/ui/scroll-progress-set";

// 追蹤整個頁面的頂部進度條
<ScrollProgress variant="bar" />

// 追蹤某個 overflow 容器
const scrollerRef = React.useRef<HTMLDivElement>(null);

<div ref={scrollerRef} className="h-[400px] overflow-y-auto">
  <ScrollProgress variant="ring" container={scrollerRef} />
  {/* 內容 */}
</div>

dots 變體需要提供 sections,其 id 必須對應頁面中同名元素的 id

const sections: ScrollSection[] = [
  { id: "intro", label: "簡介" },
  { id: "usage", label: "使用" },
];

<ScrollProgress variant="dots" container={scrollerRef} sections={sections} />

<section id="intro">…</section>
<section id="usage">…</section>

Props

Prop型別預設值說明
variant"bar" | "ring" | "dots""bar"進度呈現形式:頂部細條、右下圓環、右側章節節點
containerRefObject<HTMLElement | null>巢狀捲動容器的 ref;未提供時以視窗為捲動容器
sectionsScrollSection[][]dots 變體的章節清單,id 需對應頁面元素、label 為可選標籤
classNamestring附加到最外層容器的 class

細節

  • 共用進度:三種變體都綁定同一個 scrollYProgressbarscaleXorigin-left)伸展,ringstrokeDashoffset 收合並在中央顯示百分比,dots 依章節可見比例點亮當前段。
  • 容器模式:傳入 container 時,以 ResizeObserver 量測容器可視高度,並用一個 sticky 錨點承載覆蓋層,讓指示器在容器內捲動時始終貼齊可視區;量測完成前不繪製,避免錯位。
  • 章節偵測dots 使用 IntersectionObserver 觀察各章節元素,選出可見比例最高者為當前段;作用中的節點放大,並以 layoutId 讓外圈指示在節點之間連續滑動。
  • 彈簧平滑:進度值經 useSpring 平滑,捲動停止後仍會柔順地追上目標。
  • 元件將 IntersectionObserverResizeObserver 與 Motion 事件監聽在卸載時全數清理。

可及性

  • barringrole="progressbar" 與即時更新的 aria-valuenow(0–100)。
  • dotsnav 內的可聚焦按鈕,帶 aria-labelaria-current;點擊即平滑捲動至對應段落,並提供鍵盤聚焦環。
  • 使用者系統開啟「減少動態效果」時,進度仍隨捲動更新,只是省去彈簧平滑與平滑捲動。

On this page