PlayerController is a reactive controller that consumes the player store from playerContext . Without a selector it returns the store instance directly (no subscription — use this for actions). With a selector it returns the selected value and subscribes to changes, triggering a host update on shallow-equal change. Access the current value via .value, which returns undefined until connected to a provider.
Examples
Basic Usage
Play
Pause
50% Volume
Paused: Yes | Time: 0.0s | Volume: 100%
< demo-ctrl-player class = " demo-ctrl-player " >
< media-container >
< video
src = " https://stream.mux.com/BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM/highest.mp4 "
autoplay
muted
playsinline
></ video >
< div class = " panel " >
< demo-ctrl-actions class = " actions " >
< button type = " button " class = " play " > Play </ button >
< button type = " button " class = " pause " > Pause </ button >
< button type = " button " class = " volume " > 50% Volume </ button >
</ demo-ctrl-actions >
< demo-ctrl-state class = " state " >
< span class = " text " > Paused: Yes | Time: 0.0s | Volume: 100% </ span >
</ demo-ctrl-state >
</ div >
</ media-container >
</ demo-ctrl-player >
. demo-ctrl-player {
position : relative ;
}
. demo-ctrl-player video {
width : 100 % ;
}
. panel {
display : flex ;
gap : 16 px ;
padding : 12 px ;
background : rgba ( 0 , 0 , 0 , 0.05 );
border-top : 1 px solid rgba ( 0 , 0 , 0 , 0.1 );
align-items : center ;
}
. actions {
display : flex ;
gap : 6 px ;
}
. actions button {
padding : 4 px 12 px ;
border-radius : 6 px ;
border : 1 px solid # ccc ;
background : white ;
cursor : pointer ;
font-size : 0.8125 rem ;
}
. state {
font-size : 0.8125 rem ;
color : # 374151 ;
font-variant-numeric : tabular-nums ;
}
import { applyElementProps , createButton , createPlayer , MediaElement } from ' @videojs/html ' ;
import { videoFeatures } from ' @videojs/html/video ' ;
import ' @videojs/html/media/container ' ;
const { ProviderMixin , PlayerController , context } = createPlayer ( {
features : videoFeatures ,
} ) ;
class DemoPlayer extends ProviderMixin ( MediaElement ) {
static readonly tagName = ' demo-ctrl-player ' ;
}
class PlayerActions extends MediaElement {
static readonly tagName = ' demo-ctrl-actions ' ;
readonly #player = new PlayerController ( this , context ) ;
#disconnect : AbortController | null = null ;
override connectedCallback () : void {
super . connectedCallback () ;
this . #disconnect = new AbortController () ;
const signal = this . #disconnect . signal ;
const playBtn = this . querySelector < HTMLButtonElement > ( ' .play ' ) ! ;
const pauseBtn = this . querySelector < HTMLButtonElement > ( ' .pause ' ) ! ;
const volumeBtn = this . querySelector < HTMLButtonElement > ( ' .volume ' ) ! ;
const bind = ( el : HTMLElement , action : () => void ) => {
const props = createButton ( { onActivate : action , isDisabled : () => ! this . #player . value } ) ;
applyElementProps ( el , props , signal ) ;
};
bind ( playBtn , () => this . #player . value ?. play ()) ;
bind ( pauseBtn , () => this . #player . value ?. pause ()) ;
bind ( volumeBtn , () => this . #player . value ?. setVolume ( 0.5 )) ;
}
override disconnectedCallback () : void {
super . disconnectedCallback () ;
this . #disconnect ?. abort () ;
this . #disconnect = null ;
}
}
class PlayerState extends MediaElement {
static readonly tagName = ' demo-ctrl-state ' ;
readonly #state = new PlayerController ( this , context , ( s ) => ( {
paused : s . paused ,
currentTime : s . currentTime ,
volume : s . volume ,
} )) ;
protected override update () : void {
super . update () ;
const state = this . #state . value ;
if ( ! state ) return ;
const el = this . querySelector ( ' .text ' ) ;
if ( el ) {
el . textContent = ` Paused: ${ state . paused ? ' Yes ' : ' No '} | Time: ${ state . currentTime . toFixed ( 1 ) } s | Volume: ${ Math . round ( state . volume * 100 ) } % ` ;
}
}
}
customElements . define ( DemoPlayer . tagName , DemoPlayer ) ;
customElements . define ( PlayerActions . tagName , PlayerActions ) ;
customElements . define ( PlayerState . tagName , PlayerState ) ;
API Reference Without Selector Parameters
Parameter Type Default Details host* PlayerControllerHost —
▸
Description The host element that owns this controller. context* PlayerContext<Store> —
▸
Description Player context to resolve the store from.
Return Value
Property Type Details value Result | undefined displayName string | undefined
With Selector Parameters
Parameter Type Default Details host* PlayerControllerHost —
▸
Description The host element that owns this controller. context* PlayerContext<Store> —
▸
Description Player context to resolve the store from. selector* Selector<InferStoreState<Store>, Result> —
▸
Description Derives a value from the player store state.
Return Value
Property Type Details value Result | undefined displayName string | undefined