滾動效果

Scroll Timeline

滾動驅動的時間軸,主軸生長線隨捲動延伸,抵達的節點同步亮起並揭示內容。

把這個效果裝進你的專案

在專案資料夾執行指令,CLI 會加入原始碼與依賴套件,再依下方使用範例引用元件。

npx webberui@latest add scroll-timeline

還沒有專案,或安裝遇到問題?看快速開始 →

Scroll Timeline 是用 React、Tailwind CSS 與 Motion 的 useScroll 做的捲動時間軸(scroll timeline/滾動進度時間軸)元件:左側主軸的線條隨捲動往下延伸,到達的節點同步亮起,內容由淡轉亮;結構是語意化的 ol 清單。

Playground

即時調整 props、程式碼片段同步更新——直接試出你要的樣子再複製。

0.5
編輯中的呼叫預設屬性
<ScrollTimeline/>

完整範例包含預覽的排版與資料。先安裝元件,再把範例檔貼入你的專案。

適用情境

  • 公司「關於我們」頁的發展歷程或里程碑。
  • 產品 roadmap 或更新日誌,依季度或版本列出。
  • 導入流程、申請步驟這類需要依序閱讀的說明頁。
  • 個人履歷或作品集的經歷區塊。

安裝

npx webberui@latest add https://webberui.com/r/scroll-timeline.json

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

使用

以 ScrollTimeline 包裹一組 ScrollTimelineItem。捲動時中央主軸的生長線會由上往下延伸,抵達的節點同步亮起。

import { Flag, Rocket } from "lucide-react";
import {
  ScrollTimeline,
  ScrollTimelineItem,
} from "@/components/ui/scroll-timeline";

<ScrollTimeline>
  <ScrollTimelineItem icon={<Flag />} date="2024 · Q1" title="專案啟動">
    確立動畫優先的設計原則。
  </ScrollTimelineItem>
  <ScrollTimelineItem icon={<Rocket />} date="2025 · Q1" title="正式上線">
    捲動至此,節點隨生長線一同亮起。
  </ScrollTimelineItem>
</ScrollTimeline>;

若時間軸放在固定高度的巢狀捲動容器內,將該容器的 ref 傳入 container:

const scrollerRef = React.useRef<HTMLDivElement>(null);

<div ref={scrollerRef} className="h-[300px] overflow-y-auto">
  <ScrollTimeline container={scrollerRef}>{/* ... */}</ScrollTimeline>
</div>;

範例

從資料陣列產生節點

節點資料通常來自 CMS 或常數檔,用 map 產生 ScrollTimelineItem 即可;icon 與 date 都是選填。

import {
  ScrollTimeline,
  ScrollTimelineItem,
} from "@/components/ui/scroll-timeline";

const releases = [
  { version: "v1.0", date: "2024 年 3 月", note: "第一個公開版本,支援專案與任務管理。" },
  { version: "v1.4", date: "2024 年 9 月", note: "新增甘特圖與 CSV 匯出。" },
  { version: "v2.0", date: "2025 年 4 月", note: "改寫權限系統,支援自訂角色。" },
];

export function Changelog() {
  return (
    <ScrollTimeline className="mx-auto max-w-xl">
      {releases.map((r) => (
        <ScrollTimelineItem key={r.version} date={r.date} title={r.version}>
          {r.note}
        </ScrollTimelineItem>
      ))}
    </ScrollTimeline>
  );
}

讓節點更早亮起

activationLine 是觸發線在視區中的位置,預設 0.5(正中央)。往下移到 0.75,節點捲到畫面下方四分之一處就會亮起,適合節點內容較短的時間軸。

<ScrollTimeline activationLine={0.75}>
  {/* ScrollTimelineItem… */}
</ScrollTimeline>

放在可用鍵盤捲動的固定高度區塊

時間軸放在側欄或對話框等固定高度區塊時,把捲動容器的 ref 傳給 container,並加上 tabIndex 與 aria-label,讓鍵盤使用者能聚焦後用方向鍵捲動。

const scrollerRef = React.useRef<HTMLDivElement>(null);

<div
  ref={scrollerRef}
  tabIndex={0}
  aria-label="專案歷程"
  className="h-[360px] overflow-y-auto rounded-xl border p-6"
>
  <ScrollTimeline container={scrollerRef}>{/* ScrollTimelineItem… */}</ScrollTimeline>
</div>

Props

ScrollTimeline

Prop型別預設值說明
childrenReact.ReactNode—放入一組 ScrollTimelineItem
containerReact.RefObject<HTMLElement | null>—巢狀 overflow 捲動容器的 ref;未提供時以視窗為捲動容器
activationLinenumber0.5觸發線在捲動視區中的位置(0=頂端、1=底端),生長線末端與節點點亮皆以此為基準
classNamestring—附加在最外層容器的 class

ScrollTimelineItem

Prop型別預設值說明
titleReact.ReactNode—節點標題
dateReact.ReactNode—時間或階段標籤,顯示在標題上方
iconReact.ReactNode—節點圖示(建議傳入 lucide-react 圖示),點亮後顯示於節點內
childrenReact.ReactNode—節點說明內文
classNamestring—附加在節點 li 上的 class

細節

  • 生長線的末端位置與各節點的點亮時機都以同一條「觸發線」(activationLine)為基準,因此無論每個節點的高度是否不同,節點永遠在生長線抵達的瞬間亮起,兩者精準同步。
  • 主軸末端帶有一顆「彗尾光點」,跟隨生長線前緣移動,強化捲動的方向感。
  • 節點與內容會隨捲動進度平滑地由淡轉亮;尚未抵達的節點維持淡色描邊的空心狀態。

可及性

  • 使用者系統開啟「減少動態效果」時,直接呈現整條點亮、內容全顯的靜態時間軸,不隨捲動變化。
  • 主軸、生長線、節點與光點皆為純裝飾,標記 aria-hidden;時間軸內容以語意化的 ol / li 結構承載,輔助科技朗讀時為完整清單。
  • 巢狀捲動容器範例加上 tabIndex 與 aria-label,讓鍵盤使用者可聚焦並以方向鍵捲動。

常見問題

可以在 Next.js App Router 使用嗎?

可以。檔案開頭已有 "use client",在 Server Component 頁面中照常 import,並把資料當作 props 與 children 傳入。

時間軸放在有捲軸的容器裡,線條不會動?

未傳 container 時,元件以整個視窗作為捲動來源。如果實際捲動的是某個 overflow-y-auto 的元素,要把那個元素的 ref 傳給 container。

節點高度不一樣,會不會對不齊?

不會。生長線的末端與每個節點的點亮時機都以同一條 activationLine 為基準,與節點高度無關,節點會在線條抵達時亮起。

怎麼改顏色?

主軸、節點與光點使用固定的 neutral 色系 Tailwind class,並附 dark: 變體。要換成品牌色,直接修改原始碼裡對應的 class;外層間距與寬度則用 className。

開啟「減少動態效果」會怎樣?

時間軸會直接以全部點亮、內容全顯的靜態樣子呈現,不隨捲動變化,也不顯示跟隨線條的光點。