HextaUI

Video player

Sürüklenebilir arama çubuğu, otomatik gizlenen denetimler, klavye kısayolları, hız, pencere içinde pencere ve tam ekranı olan bir video oynatıcı.

0:00 / --:--
import {
  VideoPlayer,
  VideoPlayerContent,
  VideoPlayerControls,
  VideoPlayerFullscreenButton,
  VideoPlayerPictureInPictureButton,
  VideoPlayerPlaybackRate,
  VideoPlayerPlayButton,
  VideoPlayerSeekBar,
  VideoPlayerSeekButton,
  VideoPlayerSpacer,
  VideoPlayerTime,
  VideoPlayerVolume,
} from "@/components/ui/video-player"

export function VideoPlayerDemo() {
  return (
    <VideoPlayer className="max-w-2xl">
      <VideoPlayerContent
        poster="https://media.w3.org/2010/05/sintel/poster.png"
        aria-label="Sintel trailer"
      >
        <source
          src="https://media.w3.org/2010/05/sintel/trailer.webm"
          type="video/webm"
        />
        <source
          src="https://media.w3.org/2010/05/sintel/trailer.mp4"
          type="video/mp4"
        />
      </VideoPlayerContent>
      <VideoPlayerControls>
        <VideoPlayerSeekBar />
        <VideoPlayerPlayButton />
        <VideoPlayerSeekButton offset={-10} />
        <VideoPlayerSeekButton offset={10} />
        <VideoPlayerVolume />
        <VideoPlayerTime />
        <VideoPlayerSpacer />
        <VideoPlayerPlaybackRate />
        <VideoPlayerPictureInPictureButton />
        <VideoPlayerFullscreenButton />
      </VideoPlayerControls>
    </VideoPlayer>
  )
}
pnpm dlx shadcn@latest add https://hextaui.com/r/video-player.json

Bileşeni, HextaUI tema token'larını ve bileşenin bağımlı olduğu tüm HextaUI bileşenlerini ekler.

import {
  VideoPlayer,
  VideoPlayerContent,
  VideoPlayerControls,
  VideoPlayerFullscreenButton,
  VideoPlayerPlayButton,
  VideoPlayerSeekBar,
  VideoPlayerSpacer,
  VideoPlayerTime,
  VideoPlayerVolume,
} from "@/components/ui/video-player"
<VideoPlayer>
  <VideoPlayerContent src="/intro.mp4" poster="/intro.jpg" />
  <VideoPlayerControls>
    <VideoPlayerSeekBar />
    <VideoPlayerPlayButton />
    <VideoPlayerVolume />
    <VideoPlayerTime />
    <VideoPlayerSpacer />
    <VideoPlayerFullscreenButton />
  </VideoPlayerControls>
</VideoPlayer>
VideoPlayer
├── VideoPlayerContent
└── VideoPlayerControls
    ├── VideoPlayerPlayButton
    ├── VideoPlayerSeekButton
    ├── VideoPlayerSeekBar
    ├── VideoPlayerTime
    ├── VideoPlayerSpacer
    ├── VideoPlayerVolume
    ├── VideoPlayerPlaybackRate
    ├── VideoPlayerCaptionsButton
    ├── VideoPlayerPictureInPictureButton
    └── VideoPlayerFullscreenButton

Çubuk

variant="bar" denetimleri sayfa yüzeyinde resmin altına koyar. Videoyu asla gizlemez veya örtmez.

import {
  VideoPlayer,
  VideoPlayerContent,
  VideoPlayerControls,
  VideoPlayerFullscreenButton,
  VideoPlayerPictureInPictureButton,
  VideoPlayerPlaybackRate,
  VideoPlayerPlayButton,
  VideoPlayerSeekBar,
  VideoPlayerSeekButton,
  VideoPlayerSpacer,
  VideoPlayerTime,
  VideoPlayerVolume,
} from "@/components/ui/video-player"

export function VideoPlayerBar() {
  return (
    <VideoPlayer variant="bar" className="max-w-2xl">
      <VideoPlayerContent
        poster="https://media.w3.org/2010/05/sintel/poster.png"
        aria-label="Sintel trailer"
      >
        <source
          src="https://media.w3.org/2010/05/sintel/trailer.webm"
          type="video/webm"
        />
        <source
          src="https://media.w3.org/2010/05/sintel/trailer.mp4"
          type="video/mp4"
        />
      </VideoPlayerContent>
      <VideoPlayerControls>
        <VideoPlayerSeekBar />
        <VideoPlayerPlayButton />
        <VideoPlayerSeekButton offset={-10} />
        <VideoPlayerSeekButton offset={10} />
        <VideoPlayerVolume />
        <VideoPlayerTime />
        <VideoPlayerSpacer />
        <VideoPlayerPlaybackRate />
        <VideoPlayerPictureInPictureButton />
        <VideoPlayerFullscreenButton />
      </VideoPlayerControls>
    </VideoPlayer>
  )
}

Minimal

Yalnızca ihtiyacınız olan parçaları kullanın. tooltips={false} hover ipuçlarını kapatır ve type="remaining" yukarı yerine geriye sayar.

import {
  VideoPlayer,
  VideoPlayerContent,
  VideoPlayerControls,
  VideoPlayerFullscreenButton,
  VideoPlayerPlayButton,
  VideoPlayerSeekBar,
  VideoPlayerSpacer,
  VideoPlayerTime,
} from "@/components/ui/video-player"

export function VideoPlayerMinimal() {
  return (
    <VideoPlayer className="max-w-md">
      <VideoPlayerContent
        src="https://media.w3.org/2010/05/sintel/trailer.mp4"
        poster="https://media.w3.org/2010/05/sintel/poster.png"
        aria-label="Sintel trailer"
      />
      <VideoPlayerControls tooltips={false}>
        <VideoPlayerSeekBar />
        <VideoPlayerPlayButton />
        <VideoPlayerTime type="remaining" />
        <VideoPlayerSpacer />
        <VideoPlayerFullscreenButton />
      </VideoPlayerControls>
    </VideoPlayer>
  )
}

Arama ofsetleri ve hızlar

offset her arama düğmesinin ne kadar atlayacağını, rates ise menüdeki hızları belirler.

import {
  VideoPlayer,
  VideoPlayerContent,
  VideoPlayerControls,
  VideoPlayerPlaybackRate,
  VideoPlayerPlayButton,
  VideoPlayerSeekBar,
  VideoPlayerSeekButton,
  VideoPlayerSpacer,
  VideoPlayerTime,
} from "@/components/ui/video-player"

export function VideoPlayerSeekOffsets() {
  return (
    <VideoPlayer className="max-w-xl">
      <VideoPlayerContent
        src="https://media.w3.org/2010/05/sintel/trailer.mp4"
        poster="https://media.w3.org/2010/05/sintel/poster.png"
        aria-label="Sintel trailer"
      />
      <VideoPlayerControls>
        <VideoPlayerSeekBar />
        <VideoPlayerSeekButton offset={-15} />
        <VideoPlayerPlayButton />
        <VideoPlayerSeekButton offset={30} />
        <VideoPlayerTime />
        <VideoPlayerSpacer />
        <VideoPlayerPlaybackRate rates={[1, 1.5, 2, 3]} />
      </VideoPlayerControls>
    </VideoPlayer>
  )
}

Sayfa geneli kısayollar

Kısayollar odak oynatıcının içindeyken çalışır. globalShortcuts ayrıca sayfada da dinler, ama bir alana yazarken, bir düğme kullanırken veya bir menü ya da dialog açıkken asla. Sayfa başına tek oynatıcı için kullanın.

import { Kbd } from "@/components/ui/kbd"
import {
  VideoPlayer,
  VideoPlayerContent,
  VideoPlayerControls,
  VideoPlayerFullscreenButton,
  VideoPlayerPlayButton,
  VideoPlayerSeekBar,
  VideoPlayerSpacer,
  VideoPlayerTime,
  VideoPlayerVolume,
} from "@/components/ui/video-player"

export function VideoPlayerGlobalShortcuts() {
  return (
    <div className="flex w-full max-w-xl flex-col items-center gap-3">
      <VideoPlayer globalShortcuts>
        <VideoPlayerContent
          src="https://media.w3.org/2010/05/sintel/trailer.mp4"
          poster="https://media.w3.org/2010/05/sintel/poster.png"
          aria-label="Sintel trailer"
        />
        <VideoPlayerControls>
          <VideoPlayerSeekBar />
          <VideoPlayerPlayButton />
          <VideoPlayerVolume />
          <VideoPlayerTime />
          <VideoPlayerSpacer />
          <VideoPlayerFullscreenButton />
        </VideoPlayerControls>
      </VideoPlayer>
      <p className="text-sm text-muted-foreground">
        Press <Kbd keys="k" /> anywhere on the page to play or pause.
      </p>
    </div>
  )
}

Altyazılar

Bir <track> ve VideoPlayerCaptionsButton ekleyin. Altyazılar oynatıcı tarafından çizilir; böylece denetimlerin arkasına gizlenmek yerine denetimler görünürken yukarı kayar. Çapraz kaynaklı bir parça için videoda crossOrigin gerekir.

import {
  VideoPlayer,
  VideoPlayerCaptionsButton,
  VideoPlayerContent,
  VideoPlayerControls,
  VideoPlayerFullscreenButton,
  VideoPlayerPlayButton,
  VideoPlayerSeekBar,
  VideoPlayerSpacer,
  VideoPlayerTime,
  VideoPlayerVolume,
} from "@/components/ui/video-player"

export function VideoPlayerCaptions() {
  return (
    <VideoPlayer className="max-w-xl">
      <VideoPlayerContent
        src="https://interactive-examples.mdn.mozilla.net/media/cc0-videos/friday.mp4"
        crossOrigin="anonymous"
        aria-label="Friday"
      >
        <track
          default
          kind="captions"
          srcLang="en"
          label="English"
          src="https://interactive-examples.mdn.mozilla.net/media/examples/friday.vtt"
        />
      </VideoPlayerContent>
      <VideoPlayerControls>
        <VideoPlayerSeekBar />
        <VideoPlayerPlayButton />
        <VideoPlayerVolume />
        <VideoPlayerTime />
        <VideoPlayerSpacer />
        <VideoPlayerCaptionsButton />
        <VideoPlayerFullscreenButton />
      </VideoPlayerControls>
    </VideoPlayer>
  )
}

Özel denetimler

useVideoPlayer oynatıcının içindeki herhangi bir bileşenden durum ve eylemleri okur. Yalnızca kullandığınızı seçin; böylece bileşen yalnızca o değer değiştiğinde yeniden işlenir.

"use client"

import { Button } from "@/components/ui/button"
import {
  formatTime,
  useVideoPlayer,
  VideoPlayer,
  VideoPlayerContent,
  VideoPlayerControls,
  VideoPlayerPlayButton,
  VideoPlayerSeekBar,
  VideoPlayerTime,
} from "@/components/ui/video-player"

const chapters = [
  { title: "The cave", time: 0 },
  { title: "Searching", time: 13 },
  { title: "The dragon", time: 31 },
]

function Chapters() {
  const seek = useVideoPlayer((player) => player.seek)
  const play = useVideoPlayer((player) => player.play)
  const currentTime = useVideoPlayer((player) => Math.floor(player.currentTime))
  const active = chapters.findLast((chapter) => chapter.time <= currentTime)

  return (
    <div className="flex flex-wrap gap-2">
      {chapters.map((chapter) => (
        <Button
          key={chapter.title}
          variant={chapter === active ? "secondary" : "outline"}
          size="sm"
          aria-pressed={chapter === active}
          onClick={() => {
            seek(chapter.time)
            play()
          }}
        >
          <span className="tabular-nums">{formatTime(chapter.time)}</span>
          {chapter.title}
        </Button>
      ))}
    </div>
  )
}

export function VideoPlayerCustomControls() {
  return (
    <VideoPlayer variant="bar" className="max-w-xl">
      <VideoPlayerContent
        src="https://media.w3.org/2010/05/sintel/trailer.mp4"
        poster="https://media.w3.org/2010/05/sintel/poster.png"
        aria-label="Sintel trailer"
      />
      <VideoPlayerControls>
        <VideoPlayerSeekBar />
        <VideoPlayerPlayButton />
        <VideoPlayerTime />
        <div className="basis-full px-1 pt-1">
          <Chapters />
        </div>
      </VideoPlayerControls>
    </VideoPlayer>
  )
}

Hata

Kaynak başarısız olduğunda oynatıcı errorMessage değerini gösterir, duyurur ve çalışamayan denetimleri devre dışı bırakır.

import {
  VideoPlayer,
  VideoPlayerContent,
  VideoPlayerControls,
  VideoPlayerPlayButton,
  VideoPlayerSeekBar,
  VideoPlayerTime,
} from "@/components/ui/video-player"

export function VideoPlayerError() {
  return (
    <VideoPlayer
      className="max-w-md"
      errorMessage="We couldn’t load this video. Check your connection and try again."
    >
      <VideoPlayerContent
        src="https://media.w3.org/2010/05/sintel/missing.mp4"
        aria-label="Missing video"
      />
      <VideoPlayerControls>
        <VideoPlayerSeekBar />
        <VideoPlayerPlayButton />
        <VideoPlayerTime />
      </VideoPlayerControls>
    </VideoPlayer>
  )
}

Sağdan sola

Etiketler sayfa dilini izler. Zaman çizelgesi ve oynatma denetimleri, platform medya oynatıcılarının yaptığı gibi soldan sağa kalır.

import {
  VideoPlayer,
  VideoPlayerContent,
  VideoPlayerControls,
  VideoPlayerFullscreenButton,
  VideoPlayerPlaybackRate,
  VideoPlayerPlayButton,
  VideoPlayerSeekBar,
  VideoPlayerSpacer,
  VideoPlayerTime,
  VideoPlayerVolume,
} from "@/components/ui/video-player"

export function VideoPlayerRtl() {
  return (
    <div dir="rtl" className="w-full max-w-xl">
      <VideoPlayer aria-label="مشغل الفيديو">
        <VideoPlayerContent
          src="https://media.w3.org/2010/05/sintel/trailer.mp4"
          poster="https://media.w3.org/2010/05/sintel/poster.png"
          aria-label="إعلان سينتل"
        />
        <VideoPlayerControls>
          <VideoPlayerSeekBar label="تقديم" />
          <VideoPlayerPlayButton
            playLabel="تشغيل"
            pauseLabel="إيقاف مؤقت"
            replayLabel="إعادة التشغيل"
          />
          <VideoPlayerVolume
            label="مستوى الصوت"
            muteLabel="كتم الصوت"
            unmuteLabel="إلغاء كتم الصوت"
          />
          <VideoPlayerTime />
          <VideoPlayerSpacer />
          <VideoPlayerPlaybackRate label="سرعة التشغيل" normalLabel="عادي" />
          <VideoPlayerFullscreenButton
            enterLabel="ملء الشاشة"
            exitLabel="الخروج من ملء الشاشة"
          />
        </VideoPlayerControls>
      </VideoPlayer>
    </div>
  )
}

Bunlar odak oynatıcının herhangi bir yerindeyken veya globalShortcuts ile sayfada çalışır. Bir değiştirici tuş basılıyken veya odak bir metin alanındayken atlanır.

TuşAction
SpaceKOynatır veya duraklatır.
J10 saniye geri gider.
L10 saniye ileri gider.
←→5 saniye geri veya ileri gider. Arama çubuğunda Shift 10 atlar.
↑↓Sesi %5 artırır veya azaltır.
MSesi kapatır veya açar.
CVideoda varsa altyazıları açar veya kapatır.
FTam ekrana girer veya çıkar.
IDesteklenen yerlerde pencere içinde pencereyi açar veya kapatır.
Shift+.Shift+,Oynatmayı hızlandırır veya yavaşlatır.
0–9Videonun %0 ile %90'ı arasına atlar.
HomeEndBaşa veya sona atlar.
  • Oynatıcı etiketli bir bölgedir. Her düğmenin durumunu izleyen bir adı (Play, Pause, Replay) ve kısayolunu içeren bir tooltip'i vardır.
  • Arama çubuğu ve ses slider'dır. Arama çubuğu değerini “3 dakikanın 1 dakika 5 saniyesi” olarak okur.
  • Kısayollardan ve video tıklamalarından gelen eylemler nazikçe duyurulur, örneğin “Paused” veya “Volume 40%”. Yükleme hataları bir uyarı olarak duyurulur.
  • Overlay varyantında denetimler, işaretçi hareketi olmadan 2,5 saniye oynatmadan sonra solarak kaybolur. Duraklatılmışken, üzerine gelirken veya klavyeyle kullanırken ve bir menü açıkken görünür kalırlar.
  • Dokunmatik ekranlarda dokunuş denetimleri gösterir veya gizler; sol ya da sağ üçte birine çift dokunuş 10 saniye geri veya ileri gider. Her seferinde 10 saniye eklemek için dokunmaya devam edin.
  • Altyazı düğmesi aria-pressed içeren bir toggle'dır. Önce son kullandığınız parçayı, sonra tarayıcının dilindeki birini, sonra ilkini seçer.
  • Azaltılmış harekette denetimler ve geri bildirim hareket etmeden veya ölçeklenmeden solar.

Arama çubuğu ve ses Base UI slider üzerine, düğmeler ise HextaUI'ın Button, Tooltip ve Dropdown menu bileşenleri üzerine kuruludur.

PropTürVarsayılan
variantoverlay otomatik gizlenen denetimleri videonun üzerinde yüzdürür. bar onları altına koyar.
"overlay" | "bar""overlay"
shortcutsOdak oynatıcıdayken klavye kısayolları.
booleantrue
globalShortcutsAyrıca tüm sayfadaki kısayolları dinler.
booleanfalse
errorMessage
ReactNode"This video can’t be played."
ÖznitelikAçıklama
data-slot="video-player"CSS'te kökü hedefleyin.
data-variantGeçerli varyant.
data-controls"visible" veya "hidden". İmleç denetimlerle birlikte gizlenir.
data-fullscreenOynatıcı tam ekrandayken bulunur.
aria-busyOynatma veri beklerken ayarlanır.

<video> öğesi. Her video niteliğini ve <source> veya <track> alt öğelerini alır. Tıklama oynatır veya duraklatır, çift tıklama tam ekranı açıp kapatır, dokunuş denetimleri gösterir veya gizler ve her iki yana çift dokunuş arar.

PropTürVarsayılan
autoPlayAzaltılmış hareket dışında mount olduğunda oynatmayı başlatır.
booleanfalse
playsInline
booleantrue
preload
"none" | "metadata" | "auto""metadata"
doubleTapSeekDokunmatik ekranlarda her iki yana çift dokunuşun atladığı saniye. false kapatır.
number | false10
renderHLS video öğesi gibi başka bir medya öğesini yerine koyun.
ReactElement | (props, state) => ReactElement<video>
ÖznitelikAçıklama
data-slot="video-player-content"CSS'te videoyu hedefler.
PropTürVarsayılan
tooltipsHover'da her denetimin etiketini ve kısayolunu gösterir.
booleantrue
ÖznitelikAçıklama
data-slot="video-player-controls"CSS'te denetim çubuğunu hedefler.
data-hiddenOverlay denetimleri gizliyken bulunur.

Her zaman düğmelerin üstünde kendi satırını alır. Hover işaretçinin altındaki zamanı gösterir, daha açık iz ise nelerin yüklendiğini gösterir.

PropTürVarsayılan
label
string"Seek"
onValueChange
(value: number, details) => void–
onValueCommitted
(value: number, details) => void–
disabled
booleanfalse
ÖznitelikAçıklama
data-slot="video-player-seek-bar"CSS'te arama çubuğunu hedefler.
data-draggingSararken bulunur.
data-previewingHover zamanı gösterilirken denetimde bulunur.
--video-player-bufferedVideonun yüklenen kısmı, 0 ile 1 arasında.
--video-player-hoverİşaretçinin çubuk üzerindeki konumu, 0 ile 1 arasında.
PropTürVarsayılan
playLabel
string"Play"
pauseLabel
string"Pause"
replayLabel
string"Replay"
...propsvariant ve size dahil her Button prop'u.
ButtonProps–
ÖznitelikAçıklama
data-slot="video-player-play-button"CSS'te düğmeyi hedefler.
data-state"paused", "playing" veya "ended".
PropTürVarsayılan
offsetAtlanacak saniye. Negatif değerler geri gider.
number10
label
string"Forward 10 seconds"
...propsvariant ve size dahil her Button prop'u.
ButtonProps–
ÖznitelikAçıklama
data-slot="video-player-seek-button"CSS'te düğmeyi hedefler.
data-direction"backward" veya "forward".

Hover veya odakta açılan bir slider'lı sessize alma düğmesi. Dokunmatik ekranlarda yalnızca sessize alma düğmesi görünür, çünkü telefonlar sesi kendi düğmeleriyle denetler.

PropTürVarsayılan
label
string"Volume"
muteLabel
string"Mute"
unmuteLabel
string"Unmute"
ÖznitelikAçıklama
data-slot="video-player-volume"CSS'te grubu hedefleyin.
data-slot="video-player-mute-button"Sessize alma düğmesi. Ayrıca VideoPlayerMuteButton olarak da dışa aktarılır.
data-stateSessize alma düğmesinde: "muted", "low" veya "high".
PropTürVarsayılan
type
"both" | "elapsed" | "remaining" | "duration""both"
ÖznitelikAçıklama
data-slot="video-player-time"CSS'te zamanı hedefler.
data-typeGeçerli tür.
PropTürVarsayılan
rates
number[][0.5, 0.75, 1, 1.25, 1.5, 2]
label
string"Playback speed"
normalLabel
string"Normal"
ÖznitelikAçıklama
data-slot="video-player-playback-rate"CSS'te menü tetikleyicisini hedefler.

Tüm oynatıcıyı, iPhone'da ise videonun kendisini tam ekran yapar. Tam ekranın kullanılamadığı yerde hiçbir şey işlemez.

PropTürVarsayılan
enterLabel
string"Full screen"
exitLabel
string"Exit full screen"
ÖznitelikAçıklama
data-slot="video-player-fullscreen-button"CSS'te düğmeyi hedefler.
data-state"on" veya "off".

Videoda bir altyazı parçası olana kadar hiçbir şey işlemez.

PropTürVarsayılan
label
string"Captions"
ÖznitelikAçıklama
data-slot="video-player-captions-button"CSS'te düğmeyi hedefler.
data-state"on" veya "off".
data-slot="video-player-captions"Videodaki altyazı metni. Denetimlerin üstünde dururken data-lifted bulunur.

Pencere içinde pencere desteği olmayan tarayıcılarda hiçbir şey işlemez.

PropTürVarsayılan
enterLabel
string"Picture in picture"
exitLabel
string"Exit picture in picture"
ÖznitelikAçıklama
data-slot="video-player-pip-button"CSS'te düğmeyi hedefler.
data-state"on" veya "off".

Denetim satırındaki boş alanı doldurur ve ondan sonraki denetimleri sona iter.

Oynatıcının durumunu ve eylemlerini döndürür. Tek bir değer döndüren bir seçici verin.

const paused = useVideoPlayer((player) => player.paused)
const seek = useVideoPlayer((player) => player.seek)
PropTürVarsayılan
state
paused, ended, started, waiting, scrubbing, currentTime, duration, buffered, volume, muted, playbackRate, fullscreen, pictureInPicture, error, hasCaptions, captions, caption–
actions
play, pause, togglePaused, seek, seekBy, setVolume, toggleMuted, setPlaybackRate, toggleFullscreen, togglePictureInPicture, toggleCaptions–