{}}
/>
```
## 8. Headless (No UI)
### React
```tsx
import { createPlayer } from '@videojs/react';
import { features, selectPlayback, selectTime } from '@videojs/core/dom';
const { Provider: AudioProvider, usePlayer } = createPlayer({
features: [...features.audio],
});
function AudioController() {
const playback = usePlayer(selectPlayback);
const time = usePlayer(selectTime);
// Programmatic control, no UI
useEffect(() => {
if (time && time.currentTime > 60) {
playback?.pause();
}
}, [time?.currentTime, playback]);
return ;
}
```
## 9. Using Selectors
### Performance-Optimized Access
```tsx
function TimeDisplay() {
// Only re-renders when currentTime changes
const currentTime = usePlayer((s) => s.currentTime);
if (currentTime === undefined) return null;
return {formatTime(currentTime)};
}
```
### Derived Values
```tsx
function PlayState() {
// Derived value, re-renders when paused OR ended changes
const isPlaying = usePlayer((s) => !s.paused && !s.ended);
if (isPlaying === undefined) return null;
return {isPlaying ? 'Playing' : 'Stopped'};
}
```
### Cross-Feature Selection
```tsx
function DebugPanel() {
// Select across multiple properties
const debug = usePlayer((s) => ({
paused: s.paused,
currentTime: s.currentTime,
volume: s.volume,
}));
return {JSON.stringify(debug, null, 2)};
}
```
## 10. Using Mixins (HTML)
When you need custom player behavior:
```ts
import { createPlayer, MediaElement } from '@videojs/html';
import { features } from '@videojs/core/dom';
const { PlayerMixin } = createPlayer({
features: [...features.video],
});
class MyVideoPlayer extends PlayerMixin(MediaElement) {
override connectedCallback() {
super.connectedCallback();
// Custom initialization
this.addEventListener('fullscreenchange', this.#onFullscreen);
}
#onFullscreen = () => {
// Custom fullscreen handling
};
}
customElements.define('my-video-player', MyVideoPlayer);
```