輸入元件
開關變滑桿
開關與滑桿共用同一顆把手的 React 元件:開啟後把手跳上垂直或水平滑桿可拖曳調整數值,關閉時把手跳回開關,適合「啟用後再調強度」的設定。
「先啟用、再調強度」的設定,用一顆把手就交代完。關閉時把手待在開關裡;按下開關,滑桿軌道展開,把手以彈簧沿路飛過去、飛行中略微放大像跳上去一樣,落在 min 後再一路「數到」目前數值。開啟後可直接拖曳把手或點軌道調整,拖曳中把手旁出現逐位滾動的數值氣泡;再按一次開關,把手先飛回,軌道才收起。開關狀態與數值各自支援受控/非受控雙模式,滑桿可選垂直或水平。
把這個效果裝進你的專案
在專案資料夾執行指令,CLI 會加入原始碼與依賴套件,再依下方使用範例引用元件。
npx webberui@latest add switch-to-slider-morphPlayground
即時調整 props、程式碼片段同步更新——直接試出你要的樣子再複製。
500
28
100
編輯中的呼叫預設屬性
<SwitchToSliderMorph/>
完整範例包含預覽的排版與資料。先安裝元件,再把範例檔貼入你的專案。
安裝
npx webberui@latest add https://webberui.com/r/switch-to-slider-morph.json或在 components.json 設定 registries 後,改用 @webberui/switch-to-slider-morph 安裝。
使用
import { SwitchToSliderMorph } from "@/components/ui/switch-to-slider-morph";
const [on, setOn] = React.useState(false);
const [level, setLevel] = React.useState(72);
<SwitchToSliderMorph
label="專注模式"
enabled={on}
onEnabledChange={setOn}
value={level}
onValueChange={setLevel}
valueLabel={(v) => `降噪 ${v}%`}
/>Props
| Prop | 型別 | 預設值 | 說明 |
|---|---|---|---|
enabled | boolean | — | 受控的開關狀態;未提供時由元件內部管理(非受控) |
defaultEnabled | boolean | false | 非受控模式的初始開關狀態 |
onEnabledChange | (enabled: boolean) => void | — | 開關狀態變動時回呼 |
value | number | — | 受控的滑桿數值;未提供時由元件內部管理(非受控) |
defaultValue | number | min | 非受控模式的初始數值 |
onValueChange | (value: number) => void | — | 數值變動時回呼(已依 step 對齊並夾在 min–max 之間) |
min | number | 0 | 最小值 |
max | number | 100 | 最大值 |
step | number | 1 | 數值間距 |
orientation | "vertical" | "horizontal" | "vertical" | 滑桿方向 |
length | number | 160 | 滑桿軌道長度(px) |
label | string | "啟用" | 標籤文字,同時作為開關與滑桿的無障礙名稱 |
valueLabel | (value: number) => string | (v) => `${v}%` | 數值顯示格式,也用於 aria-valuetext |
countUp | boolean | true | 開啟時把手先落在 min,再「數到」目前數值 |
stiffness | number | 500 | 把手飛行彈簧的剛性 |
damping | number | 28 | 把手飛行彈簧的阻尼 |
disabled | boolean | false | 停用開關與滑桿 |
className | string | — | 透傳到最外層容器 |
細節
- 共享把手:開關裡與滑桿上的把手是同一個 motion
layoutId(包在LayoutGroup內),切換時由彈簧帶著從舊位置飛到新位置;layout 動畫本身走直線,飛行中段額外做 1 → 1.2 → 1 的縮放,看起來像「跳」過去。 - 滑桿軌道用
clip-path展開而不是真的改高度——把手飛行的落點在 render 當下量測,軌道尺寸若還是 0 會飛錯地方。關閉時軌道延後約 200ms 才收,讓把手先飛回開關。 - 拖曳改的是把手的 transform 位移,不會觸發 layout 動畫,所以跟手不延遲;用
setPointerCapture確保拖出軌道外仍持續追蹤,點軌道任一處會直接跳到該值。 - 計數只發生在「開啟那一刻」且數值大於 min 時;拖曳或按鍵會立即中止計數。
- CSS 變數:
--wb-knob-slider-accent(預設#3b82f6,開關與 fill 顏色)、--wb-knob-slider-expand(預設220ms,軌道展開時長)、--wb-knob-slider-count(預設600ms,計數時長)。
可及性
- 開關是
role="switch"的按鈕並帶aria-checked;滑桿把手是role="slider",帶aria-valuenow/aria-valuemin/aria-valuemax/aria-orientation,aria-valuetext使用valueLabel的輸出 - 兩者都以
aria-labelledby指向label;關閉時滑桿軌道對輔助科技隱藏 - 鍵盤:方向鍵 ±
step、PageUp/PageDown ±10 個 step、Home/End 跳到 min/max;開關與把手都有 focus-visible 外框 - 用開關開啟後焦點移到滑桿把手,關閉後回到開關;受控值由外部改變時不搶焦點
- 數值氣泡與標籤旁的讀數只是視覺呈現(
aria-hidden),語意由aria-valuetext提供 - 使用者系統開啟「減少動態效果」時,把手不跳、不計數,直接在新位置以 120ms 淡入,軌道改為淡入淡出