互動編排

Roving Highlight System

單一共享的變形高亮面,可跨 tabs、側欄、網格等容器在任何註冊元素間旅行,內建 roving tabindex 鍵盤導航與焦點環同步。

把這個效果裝進你的專案

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

npx webberui@latest add roving-highlight-system

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

Playground

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

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

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

安裝

npx webberui@latest add https://webberui.com/r/roving-highlight-system.json

或在 components.json 設定 registries 後,改用 @webberui/roving-highlight-system 安裝。

使用

把任意容器與其中的 RovingHighlightItem 包在同一個 RovingHighlight 內,整組便共享一面會旅行的高亮。選取跨越不同容器時,高亮面會平滑變形移動到新位置。

import {
  RovingHighlight,
  RovingHighlightItem,
} from "@/components/ui/roving-highlight-system";

<RovingHighlight defaultValue="overview" variant="solid">
  {/* 容器一:分頁列 */}
  <div className="flex gap-1">
    <RovingHighlightItem value="overview">總覽</RovingHighlightItem>
    <RovingHighlightItem value="activity">動態</RovingHighlightItem>
  </div>

  {/* 容器二:側欄 —— 高亮會從分頁列一路旅行到這裡 */}
  <div className="flex flex-col gap-1">
    <RovingHighlightItem value="inbox">收件匣</RovingHighlightItem>
    <RovingHighlightItem value="starred">已加星</RovingHighlightItem>
  </div>
</RovingHighlight>;

受控模式

傳入 value 與 onValueChange 即進入受控模式,選取狀態由外部掌握:

const [value, setValue] = React.useState("overview");

<RovingHighlight value={value} onValueChange={setValue}>
  {/* ... */}
</RovingHighlight>;

焦點跟隨選取

selectOnFocus 開啟後,方向鍵移動焦點的同時即選取(自動模式),高亮直接跟著焦點走:

<RovingHighlight defaultValue="overview" selectOnFocus>
  {/* ... */}
</RovingHighlight>

Props

RovingHighlight

Prop型別預設值說明
valuestring | null—受控選取值
defaultValuestring | nullnull非受控初始選取值
onValueChange(value: string) => void—選取變更時觸發
variant"solid" | "outline" | "underline""solid"高亮款式:填色面/外框環/底線
orientation"horizontal" | "vertical" | "both""both"方向鍵導航方向
loopbooleantrue導航到端點時是否循環回另一端
selectOnFocusbooleanfalse焦點移到項目時是否同步選取
childrenReact.ReactNode—任意容器與其中的 RovingHighlightItem

RovingHighlightItem

Prop型別預設值說明
valuestring—此項目的唯一識別值(整組不可重複)
disabledbooleanfalse停用:不可選取、跳過鍵盤導航、不成為 tab 停靠點
onSelect(value: string) => void—被選取時觸發(點擊或鍵盤 Enter/Space)
childrenReact.ReactNode—項目內容(文字、圖示等)

其餘 button 原生屬性(aria-label、onClick 等)會一併轉發到底層元素。

細節

  • 跨容器旅行:整組同時只有被選取的項目渲染高亮面,切換時舊位置卸載、新位置掛載,由 Motion 的 layoutId 共享佈局動畫接手,讓高亮跨越不同容器平滑變形移動。
  • 命名空間隔離:每個 RovingHighlight 以 LayoutGroup 為 layoutId 命名,同頁多個實例彼此的高亮不會互相配對。
  • 三款高亮:solid 填色面、outline 外框環、underline 底線,皆會旅行。

可及性

  • roving tabindex:整組僅有一個 tab 停靠點(焦點 > 選取 > 第一個可用項目),Tab 進入後以方向鍵在所有已註冊項目間漫遊,Home / End 跳至首尾,Enter / Space 選取。
  • 焦點環同步:以近似 :focus-visible 的偵測,只有鍵盤操作時才顯示焦點環;焦點環同樣是共享元素,會隨焦點跨容器變形移動。
  • 選取項目帶 aria-current="true",停用項目帶 aria-disabled 並排除於鍵盤導航之外。
  • 使用者系統開啟「減少動態效果」時,高亮與焦點環改為直接出現在新位置,不再旅行。