Video player
Ein Videoplayer mit scrubbarer Suchleiste, automatisch ausblendenden Steuerelementen, Tastenkürzeln, Geschwindigkeit, Bild-in-Bild und Vollbild.
pnpm dlx shadcn@latest add https://hextaui.com/r/video-player.jsonFügt die Komponente, die HextaUI-Theme-Tokens und alle HextaUI-Komponenten hinzu, von denen sie abhängt.
Füge die Theme-Tokens zu deinem globalen CSS hinzu, falls du das noch nicht getan hast.
Installiere die Abhängigkeiten.
pnpm add @base-ui/react @tabler/icons-react class-variance-authority cnKopiere den folgenden Code und füge ihn in dein Projekt ein.
components/ui/video-player.tsx components/ui/button.tsx components/ui/dropdown-menu.tsx components/ui/kbd.tsx components/ui/spinner.tsx components/ui/tooltip.tsx Passe die Importpfade an dein Projekt-Setup an.
Leiste
variant="bar" setzt die Steuerelemente unter das Bild auf die Seitenfläche. Sie verbergen oder verdecken das Video nie.
Minimal
Nutze nur die Teile, die du brauchst. tooltips={false} schaltet die Hover-Hinweise ab, und type="remaining" zählt herunter statt hoch.
Such-Offsets und Geschwindigkeiten
offset legt fest, wie weit jeder Such-Button springt, und rates die Geschwindigkeiten im Menü.
Seitenweite Tastenkürzel
Tastenkürzel funktionieren, solange der Fokus im Player ist. globalShortcuts lauscht auch auf der Seite, aber nie, während du in ein Feld tippst, einen Button nutzt oder ein Menü oder Dialog offen ist. Nutze es bei einem Player pro Seite.
Untertitel
Füge ein <track> und VideoPlayerCaptionsButton hinzu. Untertitel werden vom Player gezeichnet und rücken daher nach oben, solange die Steuerelemente angezeigt werden, statt dahinter zu verschwinden. Ein Cross-Origin-Track braucht crossOrigin am Video.
Eigene Steuerelemente
useVideoPlayer liest Zustand und Aktionen aus jeder Komponente im Player. Wähle nur aus, was du nutzt, damit die Komponente nur neu rendert, wenn sich dieser Wert ändert.
Fehler
Schlägt die Quelle fehl, zeigt der Player errorMessage, sagt sie an und deaktiviert die Steuerelemente, die nicht funktionieren können.
Rechts nach links
Labels folgen der Sprache der Seite. Zeitleiste und Transportsteuerung bleiben von links nach rechts, wie bei Medienplayern der Plattformen.
Diese funktionieren, solange der Fokus irgendwo im Player ist, oder mit globalShortcuts auf der Seite. Sie werden übersprungen, solange eine Modifier-Taste gehalten wird oder der Fokus in einem Textfeld ist.
| Taste | Aktion |
|---|---|
| SpaceK | Startet oder pausiert. |
| J | Springt 10 Sekunden zurück. |
| L | Springt 10 Sekunden vor. |
| ←→ | Springt 5 Sekunden zurück oder vor. In der Suchleiste springt Shift um 10. |
| ↑↓ | Stellt die Lautstärke um 5% lauter oder leiser. |
| M | Schaltet stumm oder hebt es auf. |
| C | Schaltet Untertitel ein oder aus, wenn das Video welche hat. |
| F | Wechselt in den Vollbildmodus oder verlässt ihn. |
| I | Öffnet oder schließt Bild-in-Bild, wo unterstützt. |
| Shift+.Shift+, | Beschleunigt oder verlangsamt die Wiedergabe. |
| 0–9 | Springt zu 0% bis 90% des Videos. |
| HomeEnd | Springt zum Anfang oder zum Ende. |
- Der Player ist ein beschrifteter Bereich. Jeder Button hat einen Namen, der seinem Zustand folgt (Play, Pause, Replay), und einen Tooltip mit seinem Tastenkürzel.
- Suchleiste und Lautstärke sind Slider. Die Suchleiste liest ihren Wert als „1 Minute 5 Sekunden von 3 Minuten“.
- Aktionen aus Tastenkürzeln und Videoklicks werden höflich angesagt, etwa „Paused“ oder „Volume 40%“. Ladefehler werden als Alert angesagt.
- In der Overlay-Variante blenden Steuerelemente nach 2,5 Sekunden Wiedergabe ohne Zeigerbewegung aus. Sie bleiben sichtbar, solange pausiert ist, du hoverst oder sie per Tastatur nutzt und ein Menü offen ist.
- Auf Touchscreens zeigt oder verbirgt ein Tippen die Steuerelemente, und ein Doppeltippen im linken oder rechten Drittel springt 10 Sekunden zurück oder vor. Tippe weiter, um jedes Mal 10 Sekunden hinzuzufügen.
- Der Untertitel-Button ist ein Toggle mit
aria-pressed. Er wählt den zuletzt genutzten Track, dann einen in der Sprache des Browsers, dann den ersten. - Bei reduzierter Bewegung blenden Steuerelemente und Feedback ein und aus, ohne sich zu bewegen oder zu skalieren.
Suchleiste und Lautstärke sind auf dem Base UI Slider gebaut, die Buttons auf Button, Tooltip und Dropdown menu von HextaUI.
| Prop | Typ | Standard |
|---|---|---|
variantoverlay lässt automatisch ausblendende Steuerelemente über dem Video schweben. bar setzt sie darunter. | "overlay" | "bar" | "overlay" |
shortcutsTastenkürzel, solange der Fokus im Player ist. | boolean | true |
globalShortcutsLausche auf Tastenkürzel auch auf der ganzen Seite. | boolean | false |
errorMessage | ReactNode | "This video can’t be played." |
| Attribut | Beschreibung |
|---|---|
data-slot="video-player" | Das Root in CSS ansprechen. |
data-variant | Die aktuelle Variante. |
data-controls | "visible" oder "hidden". Der Cursor verschwindet mit den Steuerelementen. |
data-fullscreen | Vorhanden, solange der Player im Vollbild ist. |
aria-busy | Gesetzt, solange die Wiedergabe auf Daten wartet. |
Das <video>-Element. Es nimmt alle Video-Attribute und <source>- oder <track>-Kinder. Ein Klick startet oder pausiert, ein Doppelklick schaltet Vollbild um, ein Tippen zeigt oder verbirgt die Steuerelemente, und ein Doppeltippen an beiden Seiten springt.
| Prop | Typ | Standard |
|---|---|---|
autoPlayStartet die Wiedergabe beim Mount, außer bei reduzierter Bewegung. | boolean | false |
playsInline | boolean | true |
preload | "none" | "metadata" | "auto" | "metadata" |
doubleTapSeekSekunden, die ein Doppeltippen an beiden Seiten auf Touchscreens springt. false schaltet es ab. | number | false | 10 |
renderTausche ein anderes Media-Element ein, etwa ein HLS-Video-Element. | ReactElement | (props, state) => ReactElement | <video> |
| Attribut | Beschreibung |
|---|---|
data-slot="video-player-content" | Das Video per CSS ansprechen. |
| Prop | Typ | Standard |
|---|---|---|
tooltipsZeige Label und Tastenkürzel jedes Steuerelements bei Hover. | boolean | true |
| Attribut | Beschreibung |
|---|---|
data-slot="video-player-controls" | Die Steuerleiste per CSS ansprechen. |
data-hidden | Vorhanden, solange Overlay-Steuerelemente verborgen sind. |
Belegt immer eine eigene Zeile über den Buttons. Hover zeigt die Zeit unter dem Zeiger, und die hellere Spur zeigt, was geladen ist.
| Prop | Typ | Standard |
|---|---|---|
label | string | "Seek" |
onValueChange | (value: number, details) => void | – |
onValueCommitted | (value: number, details) => void | – |
disabled | boolean | false |
| Attribut | Beschreibung |
|---|---|
data-slot="video-player-seek-bar" | Die Suchleiste per CSS ansprechen. |
data-dragging | Vorhanden, solange du scrubbst. |
data-previewing | Vorhanden am Steuerelement, solange die Hover-Zeit angezeigt wird. |
--video-player-buffered | Der geladene Teil des Videos, von 0 bis 1. |
--video-player-hover | Die Zeigerposition entlang der Leiste, von 0 bis 1. |
| Prop | Typ | Standard |
|---|---|---|
playLabel | string | "Play" |
pauseLabel | string | "Pause" |
replayLabel | string | "Replay" |
...propsJede Button-Prop, auch variant und size. | ButtonProps | – |
| Attribut | Beschreibung |
|---|---|
data-slot="video-player-play-button" | Den Button per CSS ansprechen. |
data-state | "paused", "playing" oder "ended". |
| Prop | Typ | Standard |
|---|---|---|
offsetSekunden, die gesprungen wird. Negative Werte gehen zurück. | number | 10 |
label | string | "Forward 10 seconds" |
...propsJede Button-Prop, auch variant und size. | ButtonProps | – |
| Attribut | Beschreibung |
|---|---|
data-slot="video-player-seek-button" | Den Button per CSS ansprechen. |
data-direction | "backward" oder "forward". |
Ein Stummschalten-Button mit einem Slider, der bei Hover oder Fokus öffnet. Auf Touchscreens erscheint nur der Stummschalten-Button, da Smartphones die Lautstärke mit eigenen Tasten steuern.
| Prop | Typ | Standard |
|---|---|---|
label | string | "Volume" |
muteLabel | string | "Mute" |
unmuteLabel | string | "Unmute" |
| Attribut | Beschreibung |
|---|---|
data-slot="video-player-volume" | Die Gruppe in CSS ansprechen. |
data-slot="video-player-mute-button" | Der Stummschalten-Button. Auch als VideoPlayerMuteButton exportiert. |
data-state | Am Stummschalten-Button: "muted", "low" oder "high". |
| Prop | Typ | Standard |
|---|---|---|
type | "both" | "elapsed" | "remaining" | "duration" | "both" |
| Attribut | Beschreibung |
|---|---|
data-slot="video-player-time" | Die Zeit per CSS ansprechen. |
data-type | Der aktuelle Typ. |
| Prop | Typ | Standard |
|---|---|---|
rates | number[] | [0.5, 0.75, 1, 1.25, 1.5, 2] |
label | string | "Playback speed" |
normalLabel | string | "Normal" |
| Attribut | Beschreibung |
|---|---|
data-slot="video-player-playback-rate" | Den Menü-Trigger per CSS ansprechen. |
Schaltet den ganzen Player in den Vollbildmodus, auf dem iPhone das Video selbst. Rendert nichts, wo Vollbild nicht verfügbar ist.
| Prop | Typ | Standard |
|---|---|---|
enterLabel | string | "Full screen" |
exitLabel | string | "Exit full screen" |
| Attribut | Beschreibung |
|---|---|
data-slot="video-player-fullscreen-button" | Den Button per CSS ansprechen. |
data-state | "on" oder "off". |
Rendert nichts, bis das Video einen Untertitel- oder Captions-Track hat.
| Prop | Typ | Standard |
|---|---|---|
label | string | "Captions" |
| Attribut | Beschreibung |
|---|---|
data-slot="video-player-captions-button" | Den Button per CSS ansprechen. |
data-state | "on" oder "off". |
data-slot="video-player-captions" | Der Untertiteltext auf dem Video. data-lifted ist vorhanden, solange er über den Steuerelementen sitzt. |
Rendert nichts in Browsern ohne Bild-in-Bild.
| Prop | Typ | Standard |
|---|---|---|
enterLabel | string | "Picture in picture" |
exitLabel | string | "Exit picture in picture" |
| Attribut | Beschreibung |
|---|---|
data-slot="video-player-pip-button" | Den Button per CSS ansprechen. |
data-state | "on" oder "off". |
Füllt den freien Platz in der Steuerzeile und schiebt die folgenden Steuerelemente ans Ende.
Gibt Zustand und Aktionen des Players zurück. Übergib einen Selector, der einen einzelnen Wert zurückgibt.
| Prop | Typ | Standard |
|---|---|---|
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 | – |
- ButtonButtons in allen Varianten und Größen, mit eingebautem Lade-, Erfolgs- und Fehlerablauf, der den Spinner bei schnellen Anfragen überspringt.
- Dropdown menuEin Menü mit Aktionen und Optionen hinter einem Button, mit Gruppen, Untermenüs, Checkbox- und Radio-Einträgen sowie Tastenkürzeln.
- KbdTastenkappen für Tastenkürzel, die auf jeder Plattform die richtigen Symbole zeigen, korrekt vorgelesen werden und sich wie echte Tasten eindrücken.
- MotionDie Easing-Kurven, Dauern und der Reduced-Motion-Check, mit denen jede Komponente animiert, plus Hooks für Größen-Morphs und gleitende Hervorhebungen.
- SpinnerEin Ladeindikator mit Ticks im Apple-Stil oder einem atmenden Ring, der vor dem Anzeigen warten und lange genug sichtbar bleiben kann, um nicht zu flackern.
- TooltipEin kurzer Hinweis bei Hover oder Tastaturfokus, der sich nach kurzer Ruhezeit öffnet, zwischen benachbarten Elementen sofort wechselt und Tastenkürzel anzeigt.