Demos
How to import
import { VideoPlayer } from '@fibrous/semi-ui-react';
Basic Usage
For basic usage, pass the video address through src and pass the video cover address through poster

Code
import { VideoPlayer } from '@fibrous/semi-ui-react';
export default function VideoPlayerDemo() {
const src = '/assets/video/vchart-show-video.mp4';
const poster = '/assets/poster2.jpeg';
return <VideoPlayer height={630} src={src} poster={poster} />;
}Set controls list
Set the display items of the menu bar through controlsList. The accepted value is an array. The default value is ['play', 'next', 'time', 'volume', 'playbackRate', 'quality', 'route', 'mirror', 'fullscreen', 'pictureInPicture']
A control shows when controlsList allows it and the prop it depends on is provided: next needs onNext, quality needs a non-empty qualityList, and route needs a non-empty routeList; the other controls depend only on controlsList.

Code
import { VideoPlayer } from '@fibrous/semi-ui-react';
export default function VideoPlayerDemo() {
const src = '/assets/video/vchart-show-video.mp4';
const poster = '/assets/poster2.jpeg';
return <VideoPlayer height={630} src={src} poster={poster} controlsList={['play', 'time', 'volume', 'playbackRate', 'fullscreen']} />;
}Loop playback
Use loop to set loop playback

Code
import { VideoPlayer } from '@fibrous/semi-ui-react';
export default function VideoPlayerDemo() {
const src = '/assets/video/vchart-show-video.mp4';
const poster = '/assets/poster2.jpeg';
return <VideoPlayer height={630} src={src} poster={poster} loop />;
}Fast forward and rewind
Use seekTime to set the fast forward and rewind time, and use the left and right keys on the keyboard to fast forward and rewind.

Code
import { useState } from 'react';
import { VideoPlayer, Select } from '@fibrous/semi-ui-react';
export default function VideoPlayerDemo() {
const [seekTime, setSeekTime] = useState(5);
const src = '/assets/video/vchart-show-video.mp4';
const poster = '/assets/poster2.jpeg';
return (
<div>
<div>
<span style={{ marginBottom: 10 }}>请选择快进快退时间</span>
<Select
aria-label="请选择快进快退时间"
value={seekTime}
style={{ width: 100, marginLeft: 10 }}
onChange={(value) => {
if (value !== undefined) setSeekTime(value);
}}
optionList={[
{ label: '5s', value: 5 },
{ label: '10s', value: 10 },
{ label: '15s', value: 15 },
]}
placeholder="请选择快进快退时间"
/>
</div>
<VideoPlayer height={630} style={{ marginTop: 10 }} src={src} poster={poster} seekTime={seekTime} />
</div>
);
}Playback rate
Set the rate selection list through playbackRateList. The rate, quality and route controls are native buttons that open their menu when focused with Tab; see "Keyboard and focus" for the keys. Each button is named by what it sets followed by the current option (such as "Playback speed 1.0x"), and its menu items are radio items

Code
import { VideoPlayer } from '@fibrous/semi-ui-react';
export default function VideoPlayerDemo() {
const playbackRateList = [
{ label: '0.5x', value: 0.5 },
{ label: '1.0x', value: 1 },
{ label: '1.5x', value: 1.5 },
{ label: '2.0x', value: 2 },
];
const src = '/assets/video/vchart-show-video.mp4';
const poster = '/assets/poster2.jpeg';
return <VideoPlayer height={630} src={src} poster={poster} playbackRateList={playbackRateList} />;
}Volume setting
Use volume to set the initial volume, the value range is 0 - 100, set muted to true to play silently. onVolumeChange is called when the user adjusts the volume

Code
import { VideoPlayer } from '@fibrous/semi-ui-react';
export default function VideoPlayerDemo() {
const src = '/assets/video/vchart-show-video.mp4';
const poster = '/assets/poster2.jpeg';
return <VideoPlayer height={630} src={src} poster={poster} muted />;
}Clarity switching
Use qualityList to set the clarity selection list, defaultQuality to set the initial selected clarity, and onQualityChange to set the src logic to be updated after clicking.
Similarly for route switching, use routeList to set the route selection list, defaultRoute to set the initial selected route, and onRouteChange to set the src logic to be updated after clicking.

Code
import { useState } from 'react';
import { VideoPlayer } from '@fibrous/semi-ui-react';
export default function VideoPlayerDemo() {
const [src, setSrc] = useState('/assets/video/vchart-show-video.mp4');
const playList = [
{
src: '/assets/video/vchart-show-video.mp4',
quality: '1080p',
},
{
src: '/assets/video/vchart-show-video.mp4',
quality: '480p',
},
];
const poster = '/assets/poster2.jpeg';
const updateVideoSource = (quality: string) => {
const source = playList.find((item) => item.quality === quality);
if (source) setSrc(source.src);
};
return (
<VideoPlayer
height={630}
src={src}
poster={poster}
defaultQuality="1080p"
qualityList={[
{ label: '1080p', value: '1080p' },
{ label: '480p', value: '480p' },
]}
onQualityChange={(quality) => {
console.log('quality change', quality);
updateVideoSource(quality);
}}
/>
);
}Chapter markers
Set chapter markers via markers

Code
import { VideoPlayer } from '@fibrous/semi-ui-react';
export default function VideoPlayerDemo() {
const src = '/assets/video/vchart-show-video.mp4';
const poster = '/assets/poster2.jpeg';
const markers = [
{
start: 0,
title: '片头',
},
{
start: 4,
title: '功能介绍',
},
{
start: 38,
title: 'Figma Plugin',
},
{
start: 51,
title: '片尾',
},
];
return <VideoPlayer height={630} src={src} poster={poster} markers={markers} />;
}Theme
Set the theme via theme, the theme only affects the background color

Code
import { VideoPlayer } from '@fibrous/semi-ui-react';
export default function VideoPlayerDemo() {
const src = '/assets/video/vchart-show-video.mp4';
const poster = '/assets/poster2.jpeg';
return <VideoPlayer src={src} poster={poster} height={630} theme="light" />;
}Using ref for control
Get the native video element via ref for more flexible control, such as synchronized playback/pause of multiple videos


Code
import { useRef } from 'react';
import { VideoPlayer, Button } from '@fibrous/semi-ui-react';
export default function VideoPlayerDemo() {
const videoRef1 = useRef<HTMLVideoElement>(null);
const videoRef2 = useRef<HTMLVideoElement>(null);
const src = '/assets/video/vchart-show-video.mp4';
const poster = '/assets/poster2.jpeg';
const handlePlayAll = () => {
const v1 = videoRef1.current;
const v2 = videoRef2.current;
if (v1) void v1.play();
if (v2) void v2.play();
};
const handlePauseAll = () => {
const v1 = videoRef1.current;
const v2 = videoRef2.current;
if (v1) v1.pause();
if (v2) v2.pause();
};
return (
<div>
<div style={{ marginBottom: 12 }}>
<Button onClick={handlePlayAll} style={{ marginRight: 8 }}>
同时播放
</Button>
<Button onClick={handlePauseAll}>同时暂停</Button>
</div>
<div style={{ display: 'flex', gap: 12 }}>
<VideoPlayer ref={videoRef1} src={src} poster={poster} height={315} width="50%" />
<VideoPlayer ref={videoRef2} src={src} poster={poster} height={315} width="50%" />
</div>
</div>
);
}Keyboard and focus
- While focus is inside the player, Space toggles play and pause, except on a button or an input control, which keeps the key; the left and right arrow keys rewind and fast forward by
seekTime, except inside an input control, the progress bar or a menu, which keep the keys. Combinations with Alt, Ctrl or Meta are ignored. - The progress bar is a slider (
role="slider"): the arrow keys move it byseekTime, PageUp and PageDown by a tenth of the duration, and Home and End jump to either end. Screen readers announce "current time / total time". - The playback rate, quality and route buttons open their menu when focused with Tab; the down and up arrow keys move focus to the first and last item. In the menu, the up and down arrow keys, Home and End move focus, Enter or Space selects, and Esc closes the menu and returns to the button.
- The volume popover opens when the volume button receives focus, and Enter or Space toggles mute; the down arrow key moves focus into the popover, where the volume slider takes the arrow keys.
- When the pointer leaves the player during playback, the control bar stays visible while it holds keyboard focus.
API
Props
| Property | Description | Type | Default |
|---|---|---|---|
| autoPlay | Whether to play automatically. | boolean | false |
| captionsSrc | Captions source URL; the captions are shown by default once set. | string | - |
| className | Class name of the root element. | string | - |
| clickToPlay | Whether clicking the video toggles playback. | boolean | true |
| controlsList | Controls shown in the control bar, all by default. A control also needs the prop it depends on to show. | VideoControl[] | Type["play", "next", "time", "volume", "playbackRate", "quality", "route", "mirror", "fullscreen", "pictureInPicture"] |
| crossOrigin | CORS setting of the video element: anonymous or use-credentials; an empty string means anonymous. | TypeReact.MediaHTMLAttributes<HTMLVideoElement>['crossOrigin'] | - |
| defaultPlaybackRate | Initial playback rate, read once when the player mounts. | number | 1 |
| defaultQuality | Initial quality, read once when the player mounts. | string | - |
| defaultRoute | Initial route, read once when the player mounts. | string | - |
| height | Player height; a number is in pixels, a string is used as is. | number | string | - |
| loop | Whether to loop playback. | boolean | false |
| markers | Chapter markers, each with a start time start in seconds and a title title. | VideoPlayerMarker[] | - |
| muted | Whether to start muted, read once when the player mounts. | boolean | false |
| onNext | Called when the next button is clicked. The button shows only when this is set and controlsList includes next. | Type() => void | - |
| onPause | Called when playback pauses. | Type() => void | - |
| onPlay | Called when playback starts. | Type() => void | - |
| onQualityChange | Called when the quality changes, with the selected quality value. | Type(quality: string) => void | - |
| onRateChange | Called when the playback rate changes, with the selected rate. | Type(rate: number) => void | - |
| onRouteChange | Called when the route changes, with the selected route value. | Type(route: string) => void | - |
| onVolumeChange | Called when the user drags the volume slider or toggles mute, with the new volume (0 when muted); not called on initialization. | Type(volume: number) => void | - |
| playbackRateList | Playback rate options, by default 2.0, 1.5, 1.25, 1.0 and 0.75. | TypeVideoPlayerOption<number>[] | - |
| poster | Poster image URL. | string | - |
| qualityList | Quality options; the quality control shows only when this is non-empty. | TypeVideoPlayerOption<string>[] | - |
| ref | Reference to the native video element, for more flexible control; either a ref object or a callback. | TypeReact.Ref<HTMLVideoElement> | - |
| routeList | Route options; the route control shows only when this is non-empty. | TypeVideoPlayerOption<string>[] | - |
| seekTime | Seconds a fast forward or rewind moves. | number | 10 |
| src | Video URL. Without it a missing-resource message shows; removing it keeps the previous source on the video element. | string | - |
| style | Inline style of the root element, applied after width and height, so it overrides them. | React.CSSProperties | - |
| theme | Theme, affecting only the background color: dark or light. | VideoPlayerTheme | "dark" |
| volume | Initial volume from 0 to 100, read once when the player mounts. | number | 100 |
| width | Player width; a number is in pixels, a string is used as is. | number | string | - |
Other native attributes (such as id, aria-*, onClick) fall through to the root div. When the root has aria-label or aria-labelledby it gets role="group", and a role you pass takes precedence. Media events (onTimeUpdate and so on) do not bubble to the root, so listening to them on the component is not supported; get the native element through ref and listen on it instead.
Marker
| Properties | Description | Type | Default Value |
|---|---|---|---|
| start | start time point | number | - |
| title | title | string | - |
VideoPlayerOption
The option type of playbackRateList is VideoPlayerOption<number>, and the option type of qualityList and routeList is VideoPlayerOption<string>. The type of value is the generic parameter.
| Properties | Description | Type | Default Value |
|---|---|---|---|
| label | Name shown in the menu | string | - |
| value | Option value, passed to the callback | T | - |
Design Token
| Sass variable | Value | Usage |
|---|---|---|
| $animation_duration-videoPlayer_controls-show | 500ms | videoPlayer菜单栏-弹出动画-动画持续时间 |
| $animation_duration-videoPlayer_slider-in | 300ms | videoPlayer进度条-弹出动画-动画持续时间 |
| $animation_function-videoPlayer_slider-in | cubic-bezier(0.62, 0.05, 0.36, 0.95) | videoPlayer进度条-弹出动画-动画插值函数 |
| $animation_function-videoPlayer_slider-out | cubic-bezier(0.62, 0.05, 0.36, 0.95) | videoPlayer进度条-收起动画-动画插值函数 |
| $color-videoPlayer_theme_dark-text | var(--semi-color-bg-0) | dark theme 字体色 |
| $color-videoPlayer_theme_dark-bg | var(--semi-grey-8) | dark theme 背景色 |
| $color-videoPlayer_theme_light-text | var(--semi-grey-8) | light theme 字体色 |
| $color-videoPlayer_theme_light-bg | var(--semi-color-disabled-bg) | light theme 背景色 |
| $color-videoPlayer_pause-bg | var(--semi-color-text-1) | 暂停按钮颜色 |
| $color-videoPlayer_notification-bg | var(--semi-color-overlay-bg) | notification 背景色 |
| $color-videoPlayer_notification-text | var(--semi-color-default) | notification 字体色 |
| $color-videoPlayer_controls-bg | rgba(28, 31, 35, 0.8) | 控制栏背景色 |
| $color-videoPlayer_controls-text | #fff | 控制栏文字色 |
| $color-videoPlayer_controls_popup-bg | rgb(46, 50, 56) | 音量弹层与菜单背景色 |
| $color-videoPlayer_controls_item_popup-bg-default | var(--semi-color-overlay-bg) | 控制栏弹层背景色 |
| $color-videoPlayer_controls_item_popup-bg-hover | rgba(67, 68, 74, 1) | 控制栏弹层背景色 - hover |
| $color-videoPlayer_controls_popup_item-text-default | rgba(#fff, 0.7) | 控制栏文字色 |
| $color-videoPlayer_controls_popup_item-text-active | var(--semi-color-primary) | 控制栏弹层文字色 - 选中 |
| $color-videoPlayer_progress_bar-bg-played | var(--semi-color-primary) | 进度条已播放部分背景色 |
| $color-videoPlayer_progress_bar-bg-loaded | var(--semi-grey-3) | 进度条已加载部分背景色 |
| $color-videoPlayer_progress_bar-bg-unplayed | var(--semi-grey-5) | 进度条未播放部分背景色 |
| $color-videoPlayer_progress_bar_handle-bg | #fff | handle 背景色 |
| $color-videoPlayer_progress_bar_handle-border | var(--semi-color-primary) | handle 边框色 |
| $color-videoPlayer_progress_bar_handle-shadow | var(--semi-color-shadow) | handle 阴影色 |
| $height-videoPlayer_progress_bar_hotSpot-default | 20px | 进度条热区 default 高度 |
| $height-videoPlayer_progress_bar-default | 4px | 进度条 default 高度 |
| $height-videoPlayer_progress_bar-hover | 10px | 进度条 hover 高度 |
| $height-videoPlayer_progress_bar_handle | 16px | 进度条 handle 高度 |
| $height-videoPlayer_controls_menu-default | 56px | 控制栏 default 高度 |
| $height-videoPlayer_controls_volume-default | 168px | 控制栏音量 default 高度:标题 36px + 滑块 120px + 底部留白 12px |
| $height-videoPlayer_controls_popup-default | 24px | 控制栏弹层类元素 default 高度 |
| $height-videoPlayer_controls_popup_item-default | 32px | 控制栏弹层类元素 item default 高度 |
| $width-videoPlayer_controls_volume-default | 40px | 控制栏音量 default 宽度 |
| $width-videoPlayer_controls_popup_item-default | 50px | 控制栏弹层类元素 default 宽度 |
| $width-videoPlayer_controls_popup-default | 48px | 控制栏弹层 default 宽度 |
| $spacing-videoPlayer-progress_bar_chapter-marginRight | 2px | 进度条分节间距 |
| $spacing-videoPlayer_notification-bottom | 22px | notification 距离菜单栏距离 |
| $spacing-videoPlayer_notification-left | 8px | notification 距离菜单栏左侧距离 |
| $spacing-videoPlayer_notification_text-paddingY | 8px | notification 文字垂直方向 padding |
| $spacing-videoPlayer_notification_text-paddingX | 12px | notification 文字水平方向 padding |
| $spacing-videoPlayer-controls-padding | $spacing-base-tight $spacing-base | 控制栏 padding |
| $spacing-videoPlayer-controls_item-gap | $spacing-tight | 控制栏 item 间距 |
| $spacing-videoPlayer-controls_time-paddingX | 8px | 控制栏时间 paddingX |
| $spacing-videoPlayer-controls_volume_title-paddingX | 10px | 控制栏音量标题文字 paddingX |
| $spacing-videoPlayer-controls_volume_title-paddingY | 0px | 控制栏音量标题文字 paddingX |
| $spacing-videoPlayer-controls_volume_popup-paddingY | 0px | 控制栏音量弹层 paddingX |
| $spacing-videoPlayer-controls_volume_popup-paddingX | $spacing-extra-tight | 控制栏音量弹层 paddingX |
| $spacing-videoPlayer-controls_popup-paddingX | $spacing-tight | 控制栏弹层元素 paddingX |
| $spacing-videoPlayer-controls_popup-paddingY | 0px | 控制栏弹层元素 paddingY |
| $spacing-videoPlayer-progress_bar_wrapper-marginX | $spacing-tight | 进度条 wrapper marginX |
| $spacing-videoPlayer-progress_bar_wrapper-marginY | 0px | 进度条 wrapper marginY |
| $spacing-videoPlayer_progress_bar-centerY | $height-videoPlayer_progress_bar_hotSpot-default - $height-videoPlayer_progress_bar-default * 0.5 | 进度条与 handle 的中心线距热区顶部的距离,悬停变粗时上下对称 |
| $spacing-videoPlayer_error_svg-marginBottom | 12px | error svg marginBottom |
| $radius-videoPlayer_notification | 3px | notification 圆角 |
| $radius-videoPlayer_progress_bar_handle | 50% | 进度条 handle 圆角 |
| $radius-videoPlayer_progress_bar | 999px | 进度条圆角 |
| $radius-videoPlayer_controls_item | 3px | 控制栏 item 圆角 |
| $radius-videoPlayer_controls_popup | 4px | 控制栏弹层圆角 |
| $font-videoPlayer_notification-fontSize | $font-size-regular | notification 字体大小 |
| $font-videoPlayer_controls_item-fontSize | $font-size-small | 控制栏 item 字体大小 |
| $font-videoPlayer_controls_time_text-fontSize | $font-size-regular | 控制栏时间字体大小 |
| $font-videoPlayer_error-fontSize | $font-size-regular | error 字体大小 |
| $font-videoPlayer_notification-lineHeight | 20px | notification 行高 |
| $font-videoPlayer_controls_popup_item-lineHeight | 16px | 控制栏 item 行高 |
| $font-videoPlayer_controls_popup_item-fontWeight | 600 | 控制栏 item 字体粗细 |
| $font-videoPlayer_error-fontWeight | 600 | error 字体粗细 |