# usePlayer

Hook to access the player store from within a Player

## Import

```tsx
import { usePlayer } from "@videojs/react";
```

The `usePlayer` hook returned by [`createPlayer`](https://videojs.org/docs/framework/react/reference/api/create-player) gives you access to the player store from any component within its `Player`. It’s typed to the features you passed to `createPlayer`, and has two overloads — without arguments for direct store access, or with a selector for reactive state subscriptions.

```tsx
const { Player, usePlayer } = createPlayer({ features: videoFeatures });
```

The pair works exactly like React Context: [`Player`](https://videojs.org/docs/framework/react/reference/components/player) is the Provider, and `usePlayer` is its `useContext`-style consumer, so the calling component must render inside `Player`. You can still read state anywhere: `Player` renders no DOM of its own, so lift it above every component that needs player state, the way you’d lift any Provider.

`usePlayer` is also available as a standalone import (`import { usePlayer } from '@videojs/react'`), but the standalone version returns an untyped `UnknownStore`. Pass a premade selector to recover typing:

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

usePlayer();               // UnknownStore (state: unknown)
usePlayer(selectPlayback); // MediaPlaybackState | undefined
```

## Examples

### Store Access

Call `usePlayer()` without arguments to get the store instance. Use this for imperative actions like play, pause, and volume changes. The component does not re-render on state changes.

**App.tsx**

```tsx
import { Container, createPlayer } from '@videojs/react';
import { Video, videoFeatures } from '@videojs/react/video';

const { Player, usePlayer } = createPlayer({
  features: videoFeatures,
});

function Controls() {
  const store = usePlayer();

  return (
    <div className="controls">
      <button type="button" onClick={() => store.play()}>
        Play
      </button>
      <button type="button" onClick={() => store.pause()}>
        Pause
      </button>
    </div>
  );
}

export default function StoreAccess() {
  return (
    <Player>
      <Container className="media-container">
        <Video src="https://stream.mux.com/BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM/highest.mp4" autoPlay muted playsInline loop />
        <Controls />
      </Container>
    </Player>
  );
}
```

**App.css**

```css
.media-container {
  position: relative;
}

.media-container video {
  width: 100%;
}

.controls {
  display: flex;
  gap: 6px;
  padding: 12px;
  background: rgba(0, 0, 0, 0.05);
  border-top: 1px solid rgba(0, 0, 0, 0.1);
}

.controls button {
  padding: 4px 12px;
  font-size: 0.8125rem;
  color: #111827;
  cursor: pointer;
  background: white;
  border: 1px solid #ccc;
  border-radius: 6px;
}
```

### Selector Subscription

Pass a selector function to subscribe to specific state. The component re-renders when the selected value changes, using shallow equality by default.

**App.tsx**

```tsx
import { Container, createPlayer } from '@videojs/react';
import { Video, videoFeatures } from '@videojs/react/video';

const { Player, usePlayer } = createPlayer({
  features: videoFeatures,
});

function StateDisplay() {
  const state = usePlayer((s) => ({
    paused: s.paused,
    currentTime: s.currentTime,
    duration: s.duration,
  }));

  return (
    <dl className="panel">
      <div>
        <dt>Paused</dt>
        <dd>{String(state.paused)}</dd>
      </div>
      <div>
        <dt>Time</dt>
        <dd>
          {state.currentTime.toFixed(1)}s / {state.duration.toFixed(1)}s
        </dd>
      </div>
    </dl>
  );
}

export default function Selector() {
  return (
    <Player>
      <Container className="media-container">
        <Video src="https://stream.mux.com/BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM/highest.mp4" autoPlay muted playsInline loop />
        <StateDisplay />
      </Container>
    </Player>
  );
}
```

**App.css**

```css
.media-container {
  position: relative;
}

.media-container video {
  width: 100%;
}

.panel {
  display: flex;
  gap: 16px;
  padding: 12px;
  margin: 0;
  font-size: 0.8125rem;
  background: rgba(0, 0, 0, 0.05);
  border-top: 1px solid rgba(0, 0, 0, 0.1);
}

.panel div {
  display: flex;
  gap: 8px;
}

.panel dt {
  color: #6b7280;
}

.panel dd {
  margin: 0;
  font-variant-numeric: tabular-nums;
}
```

## API Reference

### Without Selector

`usePlayer(): UnknownStore`

Access the player store from within a Player.

This standalone hook has no knowledge of your configured features, so it returns an untyped `UnknownStore` whose state properties are typed as `unknown`. For typed access, use the `usePlayer` returned by `createPlayer()`, or pass a premade selector to recover the type from its return value.

#### Return Value

| Property | Type |
| --- | --- |
| `$state` | `{ current: Readonly<UnknownState>; subscribe(callback: (() => void), options?: SubscribeOptions): (() => void) }` |
| `target` | `unknown \| null` |
| `destroyed` | `boolean` |
| `state` | `Record<string, unknown>` |
| `attach` | `((target: unknown) => (() => void))` |
| `destroy` | `(() => void)` |
| `subscribe` | `((callback: StateChange, options?: SubscribeOptions) => (() => void))` |

### With Selector

`usePlayer<R>(selector): R`

Select a value from the player store. Re-renders when the selected value changes.

The selector receives `UnknownState`, so an inline selector returns `unknown`. Pass a premade selector (e.g. `selectPlayback`) to get a typed result.

#### Parameters

| Parameter | Type | Default | Description |
| --- | --- | --- | --- |
| `selector` (required) | `((state: UnknownState) => R)` | — | Derives a value from the player store state. |

#### Return Value

`R`

---

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