WebberUI

Scrollytelling Stage

左側 sticky 數據舞台+右側步驟文章的雙欄滾動敘事,舞台圖形狀態、高亮區域與註解標線依步驟索引補間 morph 切換。

載入預覽⋯

Playground

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

100
16
<ScrollytellingStage />

安裝

npx shadcn@latest add https://webberui.com/r/scrollytelling-stage.json

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

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

npm install motion clsx tailwind-merge

使用

每個 ScrollytellingStepscene 描述捲到該步驟時左側舞台應呈現的狀態;捲動時舞台會在相鄰步驟的場景之間補間 morph。

import {
  ScrollytellingStage,
  ScrollytellingStep,
} from "@/components/ui/scrollytelling-stage";

<ScrollytellingStage>
  <ScrollytellingStep title="平穩起步" scene={{ data: [30, 42, 38, 46, 40] }}>
    <p>基準線:各週活躍度大致持平。</p>
  </ScrollytellingStep>

  <ScrollytellingStep
    title="週中放量"
    scene={{
      data: [30, 55, 74, 60, 44],
      annotation: { at: 2, label: "週三高峰" },
    }}
  >
    <p>推出新功能後,週三出現單日高峰。</p>
  </ScrollytellingStep>

  <ScrollytellingStep
    title="後段承接"
    scene={{
      data: [34, 58, 70, 82, 76],
      highlight: [3, 4],
      annotation: { at: 3, label: "維持在高檔" },
    }}
  >
    <p>高亮區間顯示週四、週五站上新高。</p>
  </ScrollytellingStep>
</ScrollytellingStage>;

若捲動發生在固定高度的巢狀 overflow-y-auto 容器內,把容器的 ref 傳給 container

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

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

需要完全自訂舞台時,改用 renderStage(取代內建資料圖);它會收到目前 activeIndex 與連續步進的 progressMotionValue,0 至 步數-1):

<ScrollytellingStage
  renderStage={({ activeIndex, progress }) => (
    <MyCustomStage step={activeIndex} progress={progress} />
  )}
>
  {/* ...steps */}
</ScrollytellingStage>

Props

ScrollytellingStage

Prop型別預設值說明
childrenReactNode一組 ScrollytellingStep
containerRefObject<HTMLElement | null>巢狀 overflow 捲動容器的 ref;省略則以視窗為捲動容器
maxValuenumber100數值上限,長條高度以此正規化
stickyTopnumber16左側舞台吸頂位置(px)
renderStage(state) => ReactNode自訂舞台渲染,收到 { activeIndex, progress }
classNamestring外層容器 class
stageClassNamestring左側舞台外框 class;以 text-* 設定強調色

ScrollytellingStep

Prop型別預設值說明
sceneStageScene此步驟對應的舞台狀態(見下)
titleReactNode步驟標題
childrenReactNode步驟正文
classNamestring步驟外層 class

StageScene

欄位型別說明
datanumber[]各長條數值,依 maxValue 正規化為高度
highlight[number, number]高亮區間 [起始索引, 結束索引](含端點,可為小數);省略則不顯示
annotation{ at: number; label: string }註解標線指向第 at 根長條並顯示 label;省略則不顯示

細節

  • useScroll 追蹤右側步驟欄的捲動進度,換算成連續步進值(0 至 步數-1)作為所有補間的唯一驅動來源,因此長條高度、高亮帶與註解標線的變形永遠同步。
  • 高亮帶與註解標線使用 currentColor,可透過 stageClassNametext-* 一次設定整體強調色。
  • 註解標線鄰近的長條會漸亮為強調色,形成隨捲動移動的聚光效果。
  • 缺少 highlightannotation 的場景,對應圖元會平滑淡出,morph 不會跳動。

可及性

  • 使用者系統開啟「減少動態效果」時,舞台改為逐步驟即時切換(不補間、不做過渡),版面與內容完全不變。
  • 左側舞台帶 role="img" 與描述目前步驟的 aria-label;內部 SVG 圖元對輔助科技隱藏。
  • 步驟為語意化的有序清單(<ol><li>),作用中步驟標記 aria-current="step",並以不透明度與標題強調;鍵盤沿用瀏覽器原生捲動即可依序閱讀。

On this page