媒體

Custom Video Player

自訂控制列的影片播放器,播放時控制列自動淡出,支援進度拖曳、音量、全螢幕與鍵盤操作。

這是 WebberUI Pro 元件

下方的安裝指令需要授權才能執行,未授權時會回 401。

怎麼安裝 Pro 元件 →查看方案 →

把這個效果裝進你的專案

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

npx webberui@latest add "https://webberui.com/r/custom-video-player.json?t=<安裝 token>"

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

Custom Video Player 是用 React、Tailwind CSS 與 Motion 包裝 HTML5 <video> 的自訂影片播放器(video player)元件:以自繪控制列取代瀏覽器預設外觀,提供進度拖曳、緩衝顯示、音量、全螢幕與完整鍵盤快捷鍵。

Playground

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

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

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

適用情境

  • 產品首頁或功能頁的示範影片,需要控制列外觀與網站設計一致。
  • 線上課程、教學文件內嵌的操作錄影,使用者會頻繁拖曳進度、用鍵盤快轉。
  • 後台或 SaaS 裡播放使用者上傳的影片,包括 MediaRecorder 錄出、duration 為 Infinity 的 blob。
  • 登陸頁的靜音循環背景影片,搭配 autoPlay loop muted 使用。

安裝

npx webberui@latest add "https://webberui.com/r/custom-video-player.json?t=<安裝 token>"

或在 components.json 設定 registries 後,改用 @webberui/custom-video-player 安裝。

使用

import { CustomVideoPlayer } from "@/components/ui/custom-video-player";

<CustomVideoPlayer
  src="/videos/demo.mp4"
  poster="/videos/demo-poster.jpg"
  className="w-full max-w-2xl"
/>

自動播放時多數瀏覽器要求同時 muted:

<CustomVideoPlayer src="/videos/loop.mp4" autoPlay loop muted />

範例

播放時同步外部狀態

用 onPlayStateChange 在播放時暫停頁面上的其他動畫,或送出觀看事件。

"use client";

import * as React from "react";
import { CustomVideoPlayer } from "@/components/ui/custom-video-player";

export function ProductDemo() {
  const [playing, setPlaying] = React.useState(false);

  return (
    <div className="space-y-2">
      <CustomVideoPlayer
        src="/videos/product-tour.mp4"
        poster="/videos/product-tour.jpg"
        label="產品導覽影片"
        onPlayStateChange={setPlaying}
      />
      <p className="text-sm text-muted-foreground">
        {playing ? "播放中" : "已暫停"}
      </p>
    </div>
  );
}

直式短影音、控制列常駐

把 aspectRatio 改成 "9 / 16",並以 autoHide={false} 讓控制列一直顯示。

<CustomVideoPlayer
  src="/videos/reel.mp4"
  aspectRatio="9 / 16"
  autoHide={false}
  className="max-w-xs"
/>

播放錄影 blob

src 可以直接放 URL.createObjectURL 產生的網址,元件會自動修正 duration 為 Infinity 的情況。

"use client";

import * as React from "react";
import { CustomVideoPlayer } from "@/components/ui/custom-video-player";

export function RecordingPreview({ blob }: { blob: Blob }) {
  const [url, setUrl] = React.useState<string>();

  React.useEffect(() => {
    const next = URL.createObjectURL(blob);
    setUrl(next);
    return () => URL.revokeObjectURL(next);
  }, [blob]);

  if (!url) return null;
  return <CustomVideoPlayer src={url} label="錄影預覽" hideControlsDelay={1500} />;
}

Props

Prop型別預設值說明
srcstring—影片來源網址
posterstring—封面圖,播放前顯示
autoPlaybooleanfalse自動播放(通常需搭配 muted)
loopbooleanfalse循環播放
mutedbooleanfalse初始是否靜音
hideControlsDelaynumber2400播放中無操作幾毫秒後淡出控制列
autoHidebooleantrue是否啟用控制列自動淡出
aspectRatiostring"16 / 9"容器的 CSS aspect-ratio
labelstring"影片播放器"播放器容器的無障礙標籤
onPlayStateChange(playing: boolean) => void—播放狀態改變時的回呼
classNamestring—追加到容器的 className

細節

  • 控制列在播放且無操作時淡出並隱藏游標,游標移動、觸控、聚焦或按鍵時立即重現;暫停或播放結束時恆亮。
  • 進度條可點擊定位與拖曳刷動(使用 pointer capture,游標移出播放器仍持續生效)。
  • 內建 duration 修正:遇到 duration 為 Infinity 的串流或 MediaRecorder blob,會自動觸發重新計算,讓進度與時間顯示正確。
  • 音量滑桿平時收合,滑鼠移入或聚焦音量區時展開。

可及性

  • 使用者系統開啟「減少動態效果」時,控制列停用自動淡出並恆亮,過渡動畫時長歸零。
  • 完整鍵盤操作(聚焦播放器後):
    • 空白鍵 / K:播放/暫停
    • ← / →(或 J / L):後退/前進 5 秒
    • ↑ / ↓:音量增減
    • Home / End:跳到開頭/結尾
    • M:靜音切換 F:全螢幕切換
  • 進度條為 role="slider",帶 aria-valuemin/max/now 與 aria-valuetext;各控制鈕皆有 aria-label,靜音與全螢幕鈕以 aria-pressed 反映狀態。

常見問題

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

可以。原始碼第一行已有 "use client",在 Server Component 頁面裡照常 import 即可,不需要再包一層。

自動播放為什麼沒有作用?

多數瀏覽器只允許靜音的影片自動播放,請同時傳入 autoPlay 與 muted。元件本身也已設定 playsInline,iOS Safari 不會強制進入全螢幕。

怎麼調整控制列淡出的時間,或關掉自動淡出?

hideControlsDelay 設定播放中無操作幾毫秒後淡出(預設 2400),autoHide={false} 則讓控制列一直顯示。使用者開啟「減少動態效果」時,控制列也會恆亮。

影片會一開始就整支下載嗎?

不會。<video> 設定為 preload="metadata",載入時只讀取長度等中繼資料,按下播放後才開始緩衝。

需要哪些依賴?

motion、lucide-react、clsx 與 tailwind-merge,另外需要 @/lib/utils 的 cn。不使用 CLI 的話,切到「手動」分頁複製原始碼即可。