WebberUI

Roadmap Lane Board

Now / Next / Later 三欄泳道路線圖,項目卡以 shared layout 動畫在欄間晉升搬移,支援唯讀展示與互動拖曳。

載入預覽⋯

Playground

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

176
260
<RoadmapLaneBoard />

安裝

npx shadcn@latest add https://webberui.com/r/roadmap-lane-board.json

或在 components.json 設定 registries 後,改用 @webberui/roadmap-lane-board 安裝。

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

npm install motion lucide-react clsx tailwind-merge

使用

以資料驅動:lanes 定義由左至右的泳道,itemslaneId 歸屬到各欄。開啟 interactive 即可拖曳與用箭頭按鈕搬移。

import { RoadmapLaneBoard, type RoadmapItem } from "@/components/ui/roadmap-lane-board";

const items: RoadmapItem[] = [
  { id: "auth", laneId: "now", title: "重構登入流程", tag: "Eng" },
  { id: "billing", laneId: "next", title: "用量計費", tag: "Growth" },
  { id: "ai", laneId: "later", title: "AI 週報摘要", tag: "AI" },
];

export function Roadmap() {
  const [list, setList] = React.useState(items);
  return (
    <RoadmapLaneBoard items={list} onItemsChange={setList} interactive />
  );
}

唯讀展示只需省略 interactive 並傳入 defaultItems

<RoadmapLaneBoard defaultItems={items} />

自訂泳道與狀態色帶:

<RoadmapLaneBoard
  lanes={[
    { id: "todo", label: "待辦", accent: "#64748b" },
    { id: "doing", label: "進行中", accent: "#f59e0b" },
    { id: "done", label: "已完成", accent: "#10b981" },
  ]}
  defaultItems={items}
/>

Props

Prop型別預設值說明
lanesRoadmapLane[]Now / Next / Later泳道定義,決定欄的內容與由左至右順序
itemsRoadmapItem[]受控:目前所有項目
defaultItemsRoadmapItem[][]非受控初始項目
onItemsChange(items: RoadmapItem[]) => void項目集合變更時觸發
onItemMove(itemId, fromLaneId, toLaneId) => void單一項目跨欄搬移時觸發(同欄重排不觸發)
interactivebooleanfalse開啟拖曳與晉升按鈕;false 為唯讀展示
laneMinWidthnumber176每欄最小寬度(px),欄過窄時整體水平捲動
laneMaxHeightnumber260各欄內容區最大高度(px),超過時該欄垂直捲動
classNamestring外層容器樣式

RoadmapLane

欄位型別說明
idstring泳道唯一 id,對應 RoadmapItem.laneId
labelstring欄首顯示名稱
accentstring狀態色帶顏色(任意 CSS 色值),省略時依欄序取預設色盤

RoadmapItem

欄位型別說明
idstring項目唯一 id,欄間搬移的 shared layout 配對鍵
laneIdstring目前所在泳道 id
titlestring卡片標題
descriptionReact.ReactNode卡片描述(選填)
tagstring右上角小標籤(選填)

細節

  • 每張卡片帶有穩定的 layoutId,跨欄搬移時 Motion 以 shared layout 動畫從舊位置滑向新欄,其餘卡片同步 FLIP 補位。
  • 拖曳採原生 HTML5 drag-and-drop:懸停時依指標 Y 座標算出欄內落點並高亮目標欄,放開後插入對應位置。
  • 受控/非受控雙模式:傳入 items + onItemsChange 由外部主導,或僅傳 defaultItems 交由元件內部管理。
  • 各欄數量徽章即時反映該欄項目數;欄首色帶可依業務語意(狀態、優先級)自訂顏色。

可及性

  • 每欄為獨立 sectionaria-label 帶欄名與項目數;欄內為 role="list"、卡片為 role="listitem"
  • 觸控與鍵盤使用者可用卡片上的箭頭按鈕晉升/延後項目,按鈕帶明確 aria-label(如「將『用量計費』移至 Later」),到達首/尾欄時自動停用。
  • 跨欄搬移後以 aria-live="polite" 宣告最新狀態,輔助科技即時朗讀。
  • 使用者系統開啟「減少動態效果」時停用 shared layout 與 FLIP 動畫,搬移瞬間到位,功能不受影響。

On this page