Import
import { VolumeSlider } from ' @videojs/react ' ; import ' @videojs/html/ui/volume-slider ' ;
Anatomy
< VolumeSlider.Root >
< VolumeSlider.Track >
< VolumeSlider.Fill />
</ VolumeSlider.Track >
< VolumeSlider.Thumb />
< VolumeSlider.Preview >
< VolumeSlider.Value type = " pointer " />
</ VolumeSlider.Preview >
</ VolumeSlider.Root >
< media-volume-slider >
< media-slider-track >
< media-slider-fill ></ media-slider-fill >
</ media-slider-track >
< media-slider-thumb ></ media-slider-thumb >
< media-slider-preview >
< media-slider-value type = " pointer " ></ media-slider-value >
</ media-slider-preview >
</ media-volume-slider >
Behavior
Controls the media volume level. The slider maps its 0–100 internal range to the media’s 0–1 volume scale. When the media is muted, the fill level drops to 0 regardless of the stored volume value. When volumeAvailability is not "available", the HTML custom element receives native hidden, data-hidden, and disabled ARIA semantics; the React component returns null. This is independent of mutedAvailability, which controls whether the mute button is shown.
Styling
Use CSS custom properties to style the fill and pointer levels:
media-volume-slider :: before {
width : var ( --media-slider-fill );
}
React renders a <div> element. Add a className to style it:
. volume-slider :: before {
width : var ( --media-slider-fill );
}
Accessibility
Renders with role="slider" and an automatic aria-label that resolves to “Volume” from the active locale. Override with the label prop. Keyboard controls:
Arrow Left / Arrow Right : step by step increment
Page Up / Page Down : step by largeStep increment
Home : set volume to 0
End : set volume to max
Scroll wheel support:
Mouse wheel / trackpad scroll : adjusts volume by wheelStep increment (default 5)
Examples
Nest sub-components for full control over the slider’s DOM structure. This example includes a track, fill bar, draggable thumb, and a tooltip that shows the volume percentage on hover.
import { Container , createPlayer , MuteButton , VolumeSlider } from ' @videojs/react ' ;
import { Video , videoFeatures } from ' @videojs/react/video ' ;
const { Player } = createPlayer ( { features : videoFeatures } ) ;
export default function WithParts () {
return (
< Player >
< Container className = " media-container " >
< Video src = " https://stream.mux.com/BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM/highest.mp4 " autoPlay muted playsInline loop />
< MuteButton
className = " media-mute-button "
render = {( props , state ) => < button { ... props } > { state . muted ? ' Unmute ' : ' Mute ' } </ button > }
/>
< VolumeSlider.Root className = " media-volume-slider " >
< VolumeSlider.Track className = " media-slider-track " >
< VolumeSlider.Fill className = " media-slider-fill " />
</ VolumeSlider.Track >
< VolumeSlider.Thumb className = " media-slider-thumb " />
< VolumeSlider.Value type = " pointer " className = " media-slider-value " />
</ VolumeSlider.Root >
</ Container >
</ Player >
) ;
}
. media-container {
position : relative ;
}
. media-container video {
width : 100 % ;
}
. media-mute-button {
position : absolute ;
bottom : 10 px ;
left : 10 px ;
padding-block : 8 px ;
padding-inline : 20 px ;
color : black ;
cursor : pointer ;
background : rgba ( 255 , 255 , 255 , 0.7 );
border : 1 px solid rgba ( 255 , 255 , 255 , 0.3 );
border-radius : 9999 px ;
backdrop-filter : blur ( 10 px );
}
. media-volume-slider {
position : absolute ;
right : 10 px ;
bottom : 10 px ;
display : flex ;
align-items : center ;
width : 100 px ;
height : 20 px ;
cursor : pointer ;
}
. media-slider-track {
position : absolute ;
right : 0 ;
left : 0 ;
height : 4 px ;
background : rgba ( 255 , 255 , 255 , 0.3 );
border-radius : 9999 px ;
backdrop-filter : blur ( 10 px );
transition : height 150 ms ease ;
}
. media-volume-slider [ data-interactive ] . media-slider-track {
height : 6 px ;
}
. media-slider-fill {
position : absolute ;
top : 0 ;
left : 0 ;
width : var ( --media-slider-fill );
height : 100 % ;
background : white ;
border-radius : 9999 px ;
}
. media-slider-thumb {
position : absolute ;
left : var ( --media-slider-fill );
width : 14 px ;
height : 14 px ;
background : white ;
border-radius : 50 % ;
box-shadow : 0 1 px 3 px rgba ( 0 , 0 , 0 , 0.4 );
transform : translateX ( -50 % ) scale ( 0 );
transition : transform 150 ms ease ;
}
. media-volume-slider [ data-interactive ] . media-slider-thumb {
transform : translateX ( -50 % ) scale ( 1 );
}
. media-volume-slider [ data-dragging ] . media-slider-thumb {
transform : translateX ( -50 % ) scale ( 1.1 );
}
. media-slider-value {
position : absolute ;
bottom : 100 % ;
left : var ( --media-slider-pointer );
padding : 2 px 6 px ;
margin-bottom : 6 px ;
font-size : 12 px ;
color : white ;
white-space : nowrap ;
pointer-events : none ;
background : rgba ( 0 , 0 , 0 , 0.8 );
border-radius : 4 px ;
opacity : 0 ;
transform : translateX ( -50 % );
transition : opacity 150 ms ease ;
}
. media-volume-slider [ data-pointing ] . media-slider-value {
opacity : 1 ;
}
Unmute
Mute
< video-player class = " video-player " >
< media-container >
< video src = " https://stream.mux.com/BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM/highest.mp4 " autoplay muted playsinline loop ></ video >
< media-mute-button class = " media-mute-button " >
< span class = " muted " > Unmute </ span >
< span class = " unmuted " > Mute </ span >
</ media-mute-button >
< media-volume-slider class = " media-volume-slider " >
< media-slider-track class = " media-slider-track " >
< media-slider-fill class = " media-slider-fill " ></ media-slider-fill >
</ media-slider-track >
< media-slider-thumb class = " media-slider-thumb " ></ media-slider-thumb >
< media-slider-value type = " pointer " class = " media-slider-value " ></ media-slider-value >
</ media-volume-slider >
</ media-container >
</ video-player >
. video-player media-container {
position : relative ;
display : block ;
}
. video-player media-container video {
width : 100 % ;
}
. media-mute-button {
position : absolute ;
bottom : 10 px ;
left : 10 px ;
padding-block : 8 px ;
padding-inline : 20 px ;
color : black ;
cursor : pointer ;
background : rgba ( 255 , 255 , 255 , 0.7 );
border : 1 px solid rgba ( 255 , 255 , 255 , 0.3 );
border-radius : 9999 px ;
backdrop-filter : blur ( 10 px );
}
. media-mute-button . muted {
display : none ;
}
. media-mute-button . unmuted {
display : none ;
}
. media-mute-button [ data-muted ] . muted {
display : inline ;
}
. media-mute-button : not ([ data-muted ]) . unmuted {
display : inline ;
}
. media-volume-slider {
position : absolute ;
right : 10 px ;
bottom : 10 px ;
display : flex ;
align-items : center ;
width : 100 px ;
height : 20 px ;
cursor : pointer ;
}
. media-slider-track {
position : absolute ;
right : 0 ;
left : 0 ;
height : 4 px ;
background : rgba ( 255 , 255 , 255 , 0.3 );
border-radius : 9999 px ;
backdrop-filter : blur ( 10 px );
transition : height 150 ms ease ;
}
. media-volume-slider [ data-interactive ] . media-slider-track {
height : 6 px ;
}
. media-slider-fill {
position : absolute ;
top : 0 ;
left : 0 ;
width : var ( --media-slider-fill );
height : 100 % ;
background : white ;
border-radius : 9999 px ;
}
. media-slider-thumb {
position : absolute ;
left : var ( --media-slider-fill );
width : 14 px ;
height : 14 px ;
background : white ;
border-radius : 50 % ;
box-shadow : 0 1 px 3 px rgba ( 0 , 0 , 0 , 0.4 );
transform : translateX ( -50 % ) scale ( 0 );
transition : transform 150 ms ease ;
}
. media-volume-slider [ data-interactive ] . media-slider-thumb {
transform : translateX ( -50 % ) scale ( 1 );
}
. media-volume-slider [ data-dragging ] . media-slider-thumb {
transform : translateX ( -50 % ) scale ( 1.1 );
}
. media-slider-value {
position : absolute ;
bottom : 100 % ;
left : var ( --media-slider-pointer );
padding : 2 px 6 px ;
margin-bottom : 6 px ;
font-size : 12 px ;
color : white ;
white-space : nowrap ;
pointer-events : none ;
background : rgba ( 0 , 0 , 0 , 0.8 );
border-radius : 4 px ;
opacity : 0 ;
transform : translateX ( -50 % );
transition : opacity 150 ms ease ;
}
. media-volume-slider [ data-pointing ] . media-slider-value {
opacity : 1 ;
}
import ' @videojs/html/video/player ' ;
import ' @videojs/html/ui/container ' ;
import ' @videojs/html/ui/mute-button ' ;
import ' @videojs/html/ui/volume-slider ' ;
API Reference Root
media-volume-slider
Props
Prop Type Default Details disabledboolean—▸ Description Whether the slider is non-interactive. labelobject''▸ Description Custom label for the slider. Type { key: string; text: string } | string | ((state: SliderState) => Text | string)largeStepnumber—▸ Description Large step increment (Page Up/Down keys). maxnumber—minnumber—orientation'horizontal' | 'vertical'—▸ Description Axis of slider movement. stepnumberDEFAULT_VOLUME_STEP▸ Description Step increment for value changes (arrow keys). thumbAlignment'center' | 'edge'—▸ Description How the thumb aligns at the track edges. edge constrains the thumb within track bounds. valuenumber—wheelStepnumberDEFAULT_VOLUME_STEP▸ Description Step increment for wheel scrolling.
State
State is accessible via the render, className, and style props.
State is reflected as data attributes for CSS styling.
Property Type Details valuenumber▸ Description Current slider value in the min–max range. fillPercentnumber▸ Description Fill level as a percentage (0–100), derived from value. pointerPercentnumber▸ Description Pointer position as a percentage of the track (0–100). draggingboolean▸ Description Whether the user is actively dragging. pointingboolean▸ Description Whether the pointer is over the slider. interactiveboolean▸ Description Whether dragging, pointing, or focus is active. orientation'horizontal' | 'vertical'▸ Description Axis of slider movement. disabledboolean▸ Description Whether the slider is non-interactive. thumbAlignment'center' | 'edge'▸ Description How the thumb aligns at the track edges. volumenumber▸ Description Volume level from 0 (silent) to 1 (max). mutedboolean▸ Description Whether audio is muted. availabilityMediaFeatureAvailabilityhiddenboolean
Data attributes
Attribute Type Details data-availabilityMediaFeatureAvailabilitydata-hidden
CSS custom properties
Variable Details --media-slider-fill▸ Description Fill level percentage (0–100), representing the current volume level. --media-slider-pointer▸ Description Pointer position percentage (0–100), tracking the cursor along the slider.
Events
Event Description drag-endFired when a pointer drag ends. drag-startFired when a pointer drag starts.
Fill
media-slider-fill
Displays the filled portion from start to the current value.
Props
Prop Type Default Details classNamestring | ((state: SliderState) => string | undefined)—▸ Description Class name or function returning class name from state. renderReactElement | ((props: HTMLProps, state: SliderState) => ReactElement | null)—▸ Description Render prop for custom element. styleCSSProperties | ((state: SliderState) => CSSProperties | undefined)—▸ Description Style or function returning style from state.
Preview
media-slider-preview
Positioning container for preview content that tracks the pointer along the slider.
Props
Prop Type Default Details classNamestring | ((state: SliderState) => string | undefined)—▸ Description Class name or function returning class name from state. renderReactElement | ((props: HTMLProps, state: SliderState) => ReactElement | null)—▸ Description Render prop for custom element. styleCSSProperties | ((state: SliderState) => CSSProperties | undefined)—▸ Description Style or function returning style from state.
Data attributes
Attribute Type Details data-dragging▸ Description Present when the user is actively dragging. data-pointing▸ Description Present when the pointer is over the slider. data-interactive▸ Description Present when dragging, pointing, or focus is active. data-orientation'horizontal' | 'vertical'▸ Description Current axis of slider movement (horizontal or vertical). data-disabled▸ Description Present when the slider is non-interactive.
Thumb
media-slider-thumb
Draggable handle for setting the slider value. Receives focus and handles keyboard interaction.
Props
Prop Type Default Details classNamestring | ((state: SliderState) => string | undefined)—▸ Description Class name or function returning class name from state. renderReactElement | ((props: HTMLProps, state: SliderState) => ReactElement | null)—▸ Description Render prop for custom element. styleCSSProperties | ((state: SliderState) => CSSProperties | undefined)—▸ Description Style or function returning style from state.
Data attributes
Attribute Type Details data-dragging▸ Description Present when the user is actively dragging. data-pointing▸ Description Present when the pointer is over the slider. data-interactive▸ Description Present when dragging, pointing, or focus is active. data-orientation'horizontal' | 'vertical'▸ Description Current axis of slider movement (horizontal or vertical). data-disabled▸ Description Present when the slider is non-interactive.
Track
media-slider-track
Contains the slider's visual track and interactive hit zone.
Props
Prop Type Default Details classNamestring | ((state: SliderState) => string | undefined)—▸ Description Class name or function returning class name from state. renderReactElement | ((props: HTMLProps, state: SliderState) => ReactElement | null)—▸ Description Render prop for custom element. styleCSSProperties | ((state: SliderState) => CSSProperties | undefined)—▸ Description Style or function returning style from state.
Value
media-slider-value
Displays a formatted text representation of the slider value. Renders an <output> element.
Props
Prop Type Default Details classNamestring | ((state: SliderState) => string | undefined)—▸ Description Class name or function returning class name from state. format((value: number) => string)—▸ Description Custom formatter for the displayed value. Overrides the root's formatValue. renderReactElement | ((props: HTMLProps, state: SliderState) => ReactElement | null)—▸ Description Render prop for custom element. styleCSSProperties | ((state: SliderState) => CSSProperties | undefined)—▸ Description Style or function returning style from state. type'current' | 'pointer'—▸ Description Which slider value to display: the current position or the pointer position.
Data attributes
Attribute Type Details data-dragging▸ Description Present when the user is actively dragging. data-pointing▸ Description Present when the pointer is over the slider. data-interactive▸ Description Present when dragging, pointing, or focus is active. data-orientation'horizontal' | 'vertical'▸ Description Current axis of slider movement (horizontal or vertical). data-disabled▸ Description Present when the slider is non-interactive.