WebberUI

Theme Toggle

明暗主題切換按鈕:View Transitions 從點擊位置圓形擴散,Sun/Moon 圖示旋轉過渡。

載入預覽⋯

安裝

npx shadcn@latest add https://webberui.com/r/theme-toggle.json

安裝時會一併寫入 --wb-duration-fast--wb-ease-out CSS 變數到你的全域樣式。

安裝依賴後,複製 theme-toggle.tsx 到你的 components/ui/ 目錄,並在全域 CSS 加入:

npm install motion lucide-react clsx tailwind-merge
:root {
  --wb-duration-fast: 200ms;
  --wb-ease-out: cubic-bezier(0.22, 1, 0.36, 1);
}

View Transitions 需要的全域樣式(關閉預設 cross-fade)已由元件內部的 <style> 注入,不需要另外設定。

使用

import { ThemeToggle } from "@/components/ui/theme-toggle";

// 未受控:自動 toggle html 的 dark class 並寫入 localStorage("theme")
<ThemeToggle />

// 受控:搭配 next-themes 等主題方案
<ThemeToggle
  isDark={resolvedTheme === "dark"}
  onToggle={(next) => setTheme(next ? "dark" : "light")}
/>

Props

Prop型別預設值說明
isDarkboolean受控模式:目前是否為深色主題。不傳則元件自行管理 html.dark 與 localStorage
onToggle(next: boolean) => void切換時觸發,回傳切換後是否為深色。受控模式下請在此更新主題狀態
durationnumber500圓形擴散動畫時長(毫秒)
classNamestring額外樣式

細節

  • View Transitions 支援度:Chrome / Edge 111+、Safari 18+ 支援 document.startViewTransition;Firefox 尚未支援。不支援的瀏覽器會直接切換主題(無擴散動畫),功能完全不受影響
  • 圓形擴散:以點擊座標為圓心,半徑取到視口最遠角落的距離,對 ::view-transition-new(root) 執行 clipPath 動畫;鍵盤觸發時以按鈕中心為圓心
  • 受控模式onToggle 內的狀態更新會在 startViewTransition callback 中以 flushSync 同步套用,確保快照時機正確
  • SSR 安全:未受控時掛載後才讀取 html.dark,掛載前渲染中性圖示避免 hydration mismatch
  • 使用者系統開啟「減少動態效果」時,退化為直接切換,圖示過渡改為淡入淡出

On this page