覆蓋層與回饋

Multi Step Loader

長任務逐步勾選的清單式載入指示。

清單式的載入覆蓋層:逐步推進、把已完成的步驟勾選起來,並讓目前步驟平滑置中,上下邊緣淡出。

把這個效果裝進你的專案

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

npx webberui@latest add multi-step-loader

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

Multi Step Loader 是用 React、Tailwind CSS 與 Motion(motion/react)做的多步驟載入(multi step loader)覆蓋層:把一段長等待拆成幾個有名字的步驟,依序打勾,讓使用者知道流程走到哪裡。

Playground

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

1500
5
編輯中的呼叫預設屬性
<MultiStepLoader/>

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

適用情境

  • 建立工作區、匯入資料這類需要好幾秒的初始化流程。
  • 送出表單後等待後端串起多個服務(驗證、付款、寄送通知)的過渡畫面。
  • AI 產生內容時顯示「分析需求、擷取資料、產生草稿」這類階段文案。
  • 新手導覽或部署面板裡,以內嵌卡片顯示目前進度。
  • 不適合:需要顯示實際百分比的上傳或下載,改用 Circular Progress。

安裝

npx webberui@latest add https://webberui.com/r/multi-step-loader.json

或在 components.json 設定 registries 後,改用 @webberui/multi-step-loader 安裝。

使用

覆蓋層預設鋪滿最近的定位祖先,所以把它放進一個 relative 容器即可。用 loading 這個受控 prop 控制顯示。

import * as React from "react";
import { MultiStepLoader } from "@/components/ui/multi-step-loader";

const steps = ["連線到伺服器", "驗證身份", "同步資料", "準備就緒"];

export function Example() {
  const [loading, setLoading] = React.useState(false);

  return (
    <div className="relative h-80 w-full">
      <button onClick={() => setLoading(true)}>開始</button>
      <MultiStepLoader
        steps={steps}
        loading={loading}
        onComplete={() => setLoading(false)}
      />
    </div>
  );
}

每一步停留 duration 毫秒後推進。非循環模式抵達最後一步時會觸發 onComplete,讓你在收尾後把 loading 設回 false。

範例

等待非同步請求完成

元件的推進是依 duration 計時,跟實際請求無關;這個例子讓請求與步驟動畫都結束後才關閉覆蓋層。

import * as React from "react";
import { MultiStepLoader } from "@/components/ui/multi-step-loader";

const steps = ["上傳檔案", "解析欄位", "比對重複資料", "寫入資料庫"];

export function ImportButton() {
  const [loading, setLoading] = React.useState(false);
  const request = React.useRef<Promise<unknown> | null>(null);

  function start() {
    request.current = fetch("/api/import", { method: "POST" });
    setLoading(true);
  }

  return (
    <div className="relative h-96 w-full">
      <button onClick={start}>匯入聯絡人</button>
      <MultiStepLoader
        steps={steps}
        loading={loading}
        duration={1200}
        onComplete={async () => {
          await request.current;
          setLoading(false);
        }}
      />
    </div>
  );
}

內嵌卡片並循環播放

overlay={false} 讓元件變成帶邊框的卡片,搭配 loop 在等待時間無法預估時持續輪播。

<MultiStepLoader
  steps={["排入佇列", "建置映像檔", "執行測試", "部署到預覽環境"]}
  loading={isDeploying}
  loop
  overlay={false}
  visibleRows={3}
  className="w-full max-w-md"
/>

自訂強調色

勾選圓圈的顏色來自 --wb-loader-accent CSS 變數,可以在外層容器設定。

<div
  className="relative h-80"
  style={{ "--wb-loader-accent": "#6366f1" } as React.CSSProperties}
>
  <MultiStepLoader steps={steps} loading={loading} />
</div>

Props

Prop型別預設值說明
stepsstring[]—逐步顯示並依序勾選的載入文案
loadingboolean—是否顯示載入覆蓋層(受控)
durationnumber1500每一步停留時間(毫秒)
loopbooleanfalse抵達最後一步後是否從頭循環
visibleRowsnumber5可視區容納的列數,決定覆蓋層高度與上下淡出範圍
overlaybooleantruetrue 鋪滿定位祖先;false 為內嵌卡片
onComplete() => void—非循環且抵達最後一步時觸發一次
classNamestring—透傳到覆蓋層容器

自訂

  • 用 --wb-loader-accent CSS 變數改變勾選圓圈的強調色,預設為翠綠 #10b981。
  • overlay={false} 時元件呈現為帶邊框的內嵌卡片,適合放在流程面板裡。

可及性

  • 覆蓋層帶 role="status" 與 aria-live="polite",目前步驟以隱藏文字朗讀為「步驟名稱(第 n/總數)」。
  • 拆分後的清單對輔助科技以 aria-hidden 隱藏,避免重複朗讀。
  • 使用者系統開啟「減少動態效果」時,置中位移與旋轉動畫改為瞬時切換。

常見問題

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

可以。原始碼第一行已經是 "use client",它是用戶端元件,直接在 Server Component 頁面裡 import 即可;loading 狀態需要放在另一個用戶端元件中管理。

步驟會跟實際進度同步嗎?

不會。每一步固定停留 duration 毫秒(預設 1500)後推進,非循環模式抵達最後一步時呼叫 onComplete。要對齊真實進度,可以在 onComplete 裡等待請求完成,或依預估時間調整 duration。

覆蓋層為什麼沒有蓋住我想要的區塊?

預設 overlay 為 true,使用 absolute inset-0 鋪滿最近的定位祖先,請確認外層容器有 relative。不想要覆蓋層時改用 overlay={false}。

有考慮減少動態效果與螢幕閱讀器嗎?

有。覆蓋層帶 role="status" 與 aria-live="polite",會朗讀目前步驟與序號;系統開啟「減少動態效果」時,位移與旋轉動畫改為瞬時切換。

需要哪些依賴?

motion、lucide-react、clsx 與 tailwind-merge。不用 CLI 也可以,切到「手動」分頁複製原始碼即可。