Video player
Un lecteur vidéo avec une barre de recherche déplaçable, des contrôles qui se masquent automatiquement, des raccourcis clavier, la vitesse, l'image dans l'image et le plein écran.
pnpm dlx shadcn@latest add https://hextaui.com/r/video-player.jsonAjoute le composant, les tokens de thème HextaUI et les composants HextaUI dont il dépend.
Ajoutez les tokens de thème à votre CSS global, si ce n’est pas déjà fait.
Installez les dépendances.
pnpm add @base-ui/react @tabler/icons-react class-variance-authority cnCopiez et collez le code suivant dans votre projet.
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 Mettez à jour les chemins d’import selon la configuration de votre projet.
Barre
variant="bar" place les contrôles sous l'image, sur la surface de la page. Ils ne masquent ni ne recouvrent jamais la vidéo.
Minimal
N'utilisez que les parties dont vous avez besoin. tooltips={false} désactive les indices au survol, et type="remaining" décompte au lieu de compter.
Décalages de recherche et vitesses
offset définit la distance de saut de chaque bouton de recherche, et rates les vitesses du menu.
Raccourcis sur toute la page
Les raccourcis fonctionnent tant que le focus est dans le lecteur. globalShortcuts écoute aussi sur la page, mais jamais pendant que vous saisissez dans un champ, utilisez un bouton ou avez un menu ou un dialog ouvert. Utilisez-le pour un seul lecteur par page.
Sous-titres
Ajoutez un <track> et VideoPlayerCaptionsButton. Les sous-titres sont dessinés par le lecteur : ils remontent donc quand les contrôles s'affichent au lieu de se cacher derrière. Une piste d'origine croisée nécessite crossOrigin sur la vidéo.
Contrôles personnalisés
useVideoPlayer lit l'état et les actions depuis n'importe quel composant dans le lecteur. Ne sélectionnez que ce que vous utilisez, pour que le composant ne se re-rende que quand cette valeur change.
Erreur
Quand la source échoue, le lecteur affiche errorMessage, l'annonce et désactive les contrôles qui ne peuvent pas fonctionner.
De droite à gauche
Les labels suivent la langue de la page. La timeline et les contrôles de lecture restent de gauche à droite, comme dans les lecteurs multimédias des plateformes.
Ils fonctionnent tant que le focus est n'importe où dans le lecteur, ou sur la page avec globalShortcuts. Ils sont ignorés quand une touche de modification est maintenue ou que le focus est dans un champ de texte.
| Touche | Action |
|---|---|
| SpaceK | Lance ou met en pause. |
| J | Recule de 10 secondes. |
| L | Avance de 10 secondes. |
| ←→ | Recule ou avance de 5 secondes. Sur la barre de recherche, Shift saute de 10. |
| ↑↓ | Augmente ou diminue le volume de 5%. |
| M | Coupe ou rétablit le son. |
| C | Active ou désactive les sous-titres, quand la vidéo en a. |
| F | Entre en plein écran ou le quitte. |
| I | Ouvre ou ferme l'image dans l'image, là où elle est prise en charge. |
| Shift+.Shift+, | Accélère ou ralentit la lecture. |
| 0–9 | Saute de 0% à 90% de la vidéo. |
| HomeEnd | Saute au début ou à la fin. |
- Le lecteur est une région avec un label. Chaque bouton a un nom qui suit son état (Play, Pause, Replay) et un tooltip avec son raccourci.
- La barre de recherche et le volume sont des sliders. La barre de recherche lit sa valeur comme « 1 minute 5 secondes sur 3 minutes ».
- Les actions des raccourcis et des clics sur la vidéo sont annoncées poliment, par exemple « Paused » ou « Volume 40% ». Les erreurs de chargement sont annoncées comme une alerte.
- Dans la variante overlay, les contrôles s'estompent après 2,5 secondes de lecture sans mouvement du pointeur. Ils restent visibles en pause, pendant que vous les survolez ou les utilisez au clavier, et tant qu'un menu est ouvert.
- Sur écran tactile, un tap affiche ou masque les contrôles et un double tap sur le tiers gauche ou droit recule ou avance de 10 secondes. Continuez à taper pour ajouter 10 secondes à chaque fois.
- Le bouton de sous-titres est un toggle avec
aria-pressed. Il choisit la dernière piste utilisée, puis une dans la langue du navigateur, puis la première. - Avec la réduction des animations, les contrôles et le retour visuel apparaissent en fondu sans mouvement ni changement d'échelle.
La barre de recherche et le volume reposent sur le slider de Base UI, et les boutons sur Button, Tooltip et Dropdown menu de HextaUI.
| Prop | Type | Par défaut |
|---|---|---|
variantoverlay fait flotter des contrôles à masquage automatique sur la vidéo. bar les place en dessous. | "overlay" | "bar" | "overlay" |
shortcutsRaccourcis clavier tant que le focus est dans le lecteur. | boolean | true |
globalShortcutsÉcoute aussi les raccourcis sur toute la page. | boolean | false |
errorMessage | ReactNode | "This video can’t be played." |
| Attribut | Description |
|---|---|
data-slot="video-player" | Ciblez la racine en CSS. |
data-variant | La variante actuelle. |
data-controls | "visible" ou "hidden". Le curseur se masque avec les contrôles. |
data-fullscreen | Présent tant que le lecteur est en plein écran. |
aria-busy | Défini tant que la lecture attend des données. |
L'élément <video>. Il accepte tous les attributs de video, et des enfants <source> ou <track>. Un clic lance ou met en pause, un double clic bascule le plein écran, un tap affiche ou masque les contrôles et un double tap de chaque côté fait une recherche.
| Prop | Type | Par défaut |
|---|---|---|
autoPlayLance la lecture au montage, sauf avec la réduction des animations. | boolean | false |
playsInline | boolean | true |
preload | "none" | "metadata" | "auto" | "metadata" |
doubleTapSeekSecondes sautées par un double tap de chaque côté sur écran tactile. false le désactive. | number | false | 10 |
renderRemplace par un autre élément média, comme un élément vidéo HLS. | ReactElement | (props, state) => ReactElement | <video> |
| Attribut | Description |
|---|---|
data-slot="video-player-content" | Cible la vidéo en CSS. |
| Prop | Type | Par défaut |
|---|---|---|
tooltipsAffiche le label et le raccourci de chaque contrôle au survol. | boolean | true |
| Attribut | Description |
|---|---|
data-slot="video-player-controls" | Cible la barre de contrôle en CSS. |
data-hidden | Présent tant que les contrôles overlay sont masqués. |
Occupe toujours sa propre ligne au-dessus des boutons. Le survol affiche l'heure sous le pointeur, et la piste plus claire montre ce qui est chargé.
| Prop | Type | Par défaut |
|---|---|---|
label | string | "Seek" |
onValueChange | (value: number, details) => void | – |
onValueCommitted | (value: number, details) => void | – |
disabled | boolean | false |
| Attribut | Description |
|---|---|
data-slot="video-player-seek-bar" | Cible la barre de recherche en CSS. |
data-dragging | Présent pendant que vous déplacez le curseur de lecture. |
data-previewing | Présent sur le contrôle tant que l'heure de survol est affichée. |
--video-player-buffered | La partie chargée de la vidéo, de 0 à 1. |
--video-player-hover | La position du pointeur le long de la barre, de 0 à 1. |
| Prop | Type | Par défaut |
|---|---|---|
playLabel | string | "Play" |
pauseLabel | string | "Pause" |
replayLabel | string | "Replay" |
...propsToutes les props de Button, y compris variant et size. | ButtonProps | – |
| Attribut | Description |
|---|---|
data-slot="video-player-play-button" | Cible le bouton en CSS. |
data-state | "paused", "playing" ou "ended". |
| Prop | Type | Par défaut |
|---|---|---|
offsetSecondes à sauter. Les valeurs négatives reculent. | number | 10 |
label | string | "Forward 10 seconds" |
...propsToutes les props de Button, y compris variant et size. | ButtonProps | – |
| Attribut | Description |
|---|---|
data-slot="video-player-seek-button" | Cible le bouton en CSS. |
data-direction | "backward" ou "forward". |
Un bouton muet avec un slider qui s'ouvre au survol ou au focus. Sur écran tactile, seul le bouton muet s'affiche, car les téléphones règlent le volume avec leurs propres boutons.
| Prop | Type | Par défaut |
|---|---|---|
label | string | "Volume" |
muteLabel | string | "Mute" |
unmuteLabel | string | "Unmute" |
| Attribut | Description |
|---|---|
data-slot="video-player-volume" | Ciblez le groupe en CSS. |
data-slot="video-player-mute-button" | Le bouton muet. Aussi exporté sous le nom VideoPlayerMuteButton. |
data-state | Sur le bouton muet : "muted", "low" ou "high". |
| Prop | Type | Par défaut |
|---|---|---|
type | "both" | "elapsed" | "remaining" | "duration" | "both" |
| Attribut | Description |
|---|---|
data-slot="video-player-time" | Cible l'heure en CSS. |
data-type | Le type courant. |
| Prop | Type | Par défaut |
|---|---|---|
rates | number[] | [0.5, 0.75, 1, 1.25, 1.5, 2] |
label | string | "Playback speed" |
normalLabel | string | "Normal" |
| Attribut | Description |
|---|---|
data-slot="video-player-playback-rate" | Cible le déclencheur du menu en CSS. |
Met tout le lecteur en plein écran, ou la vidéo elle-même sur iPhone. Ne rend rien là où le plein écran n'est pas disponible.
| Prop | Type | Par défaut |
|---|---|---|
enterLabel | string | "Full screen" |
exitLabel | string | "Exit full screen" |
| Attribut | Description |
|---|---|
data-slot="video-player-fullscreen-button" | Cible le bouton en CSS. |
data-state | "on" ou "off". |
Ne rend rien tant que la vidéo n'a pas de piste de sous-titres.
| Prop | Type | Par défaut |
|---|---|---|
label | string | "Captions" |
| Attribut | Description |
|---|---|
data-slot="video-player-captions-button" | Cible le bouton en CSS. |
data-state | "on" ou "off". |
data-slot="video-player-captions" | Le texte des sous-titres sur la vidéo. data-lifted est présent tant qu'il se trouve au-dessus des contrôles. |
Ne rend rien dans les navigateurs sans image dans l'image.
| Prop | Type | Par défaut |
|---|---|---|
enterLabel | string | "Picture in picture" |
exitLabel | string | "Exit picture in picture" |
| Attribut | Description |
|---|---|
data-slot="video-player-pip-button" | Cible le bouton en CSS. |
data-state | "on" ou "off". |
Remplit l'espace libre de la rangée de contrôles, en repoussant les contrôles suivants vers la fin.
Renvoie l'état et les actions du lecteur. Passez un sélecteur qui renvoie une seule valeur.
| Prop | Type | Par défaut |
|---|---|---|
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 | – |
- ButtonDes boutons dans toutes les variantes et tailles, avec un flux de chargement, de succès et d’erreur intégré qui évite le spinner pour les requêtes rapides.
- Dropdown menuUn menu d’actions et d’options derrière un bouton, avec groupes, sous-menus, éléments case à cocher et radio, et raccourcis.
- KbdDes keycaps pour les raccourcis qui affichent les bons symboles sur chaque plateforme, se lisent correctement à voix haute et s’enfoncent comme de vraies touches.
- MotionLes courbes d’easing, les durées et la vérification de réduction des animations utilisées par chaque composant, ainsi que des hooks pour les morphs de taille et les surlignages glissants.
- SpinnerUn indicateur de chargement avec des graduations façon Apple ou un anneau qui respire, pouvant attendre avant de s’afficher et rester assez longtemps pour ne pas clignoter.
- TooltipUne courte infobulle au survol ou au focus clavier, qui s’ouvre après un bref arrêt, passe instantanément d’un voisin à l’autre et affiche les raccourcis.