# Features

The state and actions each feature adds to the player

Not every player needs to support every use case. To address this, Video.js has a concept of **features** — self-contained units of player functionality. Each one adds state properties and actions to the player. For example, “playback” adds `paused` and `play()`, “volume” adds `volume` and `setVolume()`, and so on.

## Feature bundles and presets

You probably don’t want to hand-pick every feature your player needs. A **feature bundle** groups the features needed for a specific use case into a single array.

For example, the `/video` preset configures `VideoPlayer` with `videoFeatures`, which bundles playback, volume, time, fullscreen, and more — everything a general video player needs:

```tsx
import { VideoPlayer, Video, VideoSkin } from '@videojs/react/video';

<VideoPlayer>
  <VideoSkin>
    <Video src="movie.mp4" />
  </VideoSkin>
</VideoPlayer>
```

Feature bundles are usually paired with specific skins and media elements in a **preset**. To learn more about this, and the available presets, you’ll want to check out the presets guide.

- [Learn more about presets](https://videojs.org/docs/framework/react/guides/presets)

## Individual features

If you’re not using presets, you can create a player that has individual features.

```tsx
import { createPlayer, playbackFeature, volumeFeature, timeFeature, controlsFeature } from '@videojs/react';

const { Player } = createPlayer({
  features: [playbackFeature, volumeFeature, timeFeature, controlsFeature],
});
```

## Extended feature bundles

Since feature bundles are just an array of features under the hood, it doesn’t take much to extend one. For example, if you were using the `/background` preset and wanted a play button on your background video, you might add the playback feature.

```tsx
import { createPlayer, playbackFeature } from '@videojs/react';
import { backgroundFeatures } from '@videojs/react/background';

const { Player } = createPlayer({
  features: [...backgroundFeatures, playbackFeature],
});
```

## Features inside components

You access feature state and actions through [`usePlayer`](https://videojs.org/docs/framework/react/reference/api/use-player):

```tsx
// Subscribe to state (re-renders when selected values change)
const { paused, volume } = usePlayer((s) => ({
  paused: s.paused,
  volume: s.volume,
}));

// Call actions
const store = usePlayer();
store.play();
store.setVolume(0.8);
```

## Feature selectors

Each feature also has a pre-built selector (e.g. [`selectPlayback`](https://videojs.org/docs/framework/react/reference/api/feature-playback), [`selectVolume`](https://videojs.org/docs/framework/react/reference/api/feature-volume)) that returns just that feature’s state and actions:

```tsx
import { selectPlayback, usePlayer } from '@videojs/react';

const playback = usePlayer(selectPlayback);
playback?.play();
```

## Feature availability

Volume, fullscreen, and picture-in-picture expose availability properties because platform support varies. Volume has two independent properties: `volumeAvailability` for changing the volume level and `mutedAvailability` for toggling mute. For example, iOS Safari allows muting but doesn’t allow programmatic volume control.

| Value | Meaning |
| --- | --- |
| `'available'` | Ready to use |
| `'unavailable'` | Could work, not ready yet |
| `'unsupported'` | Platform can never do this |

Components that depend on availability (like [`MuteButton`](https://videojs.org/docs/framework/react/reference/components/mute-button), [`PiPButton`](https://videojs.org/docs/framework/react/reference/components/pip-button), and [`FullscreenButton`](https://videojs.org/docs/framework/react/reference/components/fullscreen-button)) handle the three states for you:

- **`unsupported`** — the button returns `null`. No CSS needed.
- **`unavailable`** — the presentation controls stay hidden while capability detection is unresolved. Cast remains visible but disabled when its API is supported and no device is reachable.
- **`disabled` prop** — an available button stays visible and focusable with `aria-disabled="true"` plus `data-disabled` for styling.
- **`available`** — fully interactive.

Use `data-disabled` to style the non-interactive state:

```css
.pip-button[data-disabled] {
  opacity: 0.5;
  cursor: not-allowed;
}
```

You can also check availability in JS:

**PiPControl.tsx**

```tsx
function PiPControl() {
  const availability = usePlayer((s) => s.pipAvailability);

  if (availability !== 'available') return null;

  return <PiPButton />;
}
```

---

React documentation: https://videojs.org/docs/framework/react/llms.txt
All documentation: https://videojs.org/llms.txt
