Skip to main content
The player context is the internal mechanism that connects Player.Provider to the hooks and components beneath it. Most applications use the typed API returned by createPlayer — these primitives are for building custom player infrastructure or integrating with the player at a lower level.
import {
  Container,
  usePlayerContext,
  useMediaRegistration,
  type PlayerContextValue,
} from '@videojs/react';

Container

The player root element. Wraps media content and controls, and attaches the player store to the DOM when a media element is registered. Exported directly from @videojs/react and included in the result of createPlayer.
import { Container } from '@videojs/react';

<Container className="my-player" style={{ width: 640, aspectRatio: '16/9' }}>
  <video src="video.mp4" />
  <Controls />
</Container>
Container forwards a ref to the underlying HTMLDivElement and passes all standard HTMLDivElement attributes through.

ContainerProps

children
ReactNode
The media element and controls to render inside the container.
...props
HTMLAttributes<HTMLDivElement>
All standard div attributes — className, style, id, onClick, etc.
ref
Ref<HTMLDivElement>
Forwarded ref to the underlying div element.

How Container works

Internally, Container calls store.attach({ media, container }) when both the store and a registered media element are available. This wires up container-level features like fullscreen. The effect re-runs if the media element changes.
// Simplified internal implementation:
useEffect(() => {
  if (!media) return;
  return store.attach({ media, container: internalRef.current });
}, [media, store]);

usePlayerContext()

Returns the raw PlayerContextValue from the nearest Player.Provider. Throws if called outside a provider. Use this when you need simultaneous access to the store, the current media element, and the media setter — for example, when building a custom container or provider wrapper.
import { usePlayerContext } from '@videojs/react';

function CustomContainer({ children }) {
  const { store, media, setMedia } = usePlayerContext();

  // Access all three context values at once
  return <div>{children}</div>;
}

Return value

store
UnknownStore
The player store instance. Use usePlayer or useStore to subscribe to state from the store.
media
Media | null
The currently registered media element (HTMLVideoElement or HTMLAudioElement), or null if none has mounted yet.
setMedia
Dispatch<SetStateAction<Media | null>>
The React state setter for the media element. Pass this to useMediaRegistration consumers. Calling it with an element registers that element as the active media; calling it with null unregisters.

useMediaRegistration()

Returns the setMedia setter from the player context, or undefined if called outside a provider. Use this in custom media components to register an HTMLMediaElement with the player.
import { useMediaRegistration } from '@videojs/react';
import { useEffect, useRef } from 'react';

function CustomVideo({ src, ...props }) {
  const ref = useRef<HTMLVideoElement>(null);
  const setMedia = useMediaRegistration();

  useEffect(() => {
    setMedia?.(ref.current);
    return () => setMedia?.(null);
  }, [setMedia]);

  return <video ref={ref} src={src} {...props} />;
}
Only one media element should be registered per provider at a time. Registering a second element will replace the first.

Return value

setMedia
Dispatch<SetStateAction<Media | null>> | undefined
The media registration setter, or undefined if called outside a Player.Provider. Always check for undefined before calling (e.g., setMedia?.(element)).

PlayerContextValue type

The shape of the value provided by Player.Provider via React context.
import type { PlayerContextValue } from '@videojs/react';
store
UnknownStore
The player store instance created by createPlayer when Provider mounts.
media
Media | null
The registered HTMLMediaElement, or null if none has been registered.
setMedia
Dispatch<SetStateAction<Media | null>>
Setter for registering or unregistering the active media element.

Typical usage patterns

Building a custom skin

When you build a custom skin component, use Container directly rather than through createPlayer. This lets you import once and reuse across multiple player instances:
import { Container, usePlayer } from '@videojs/react';

function VideoSkin({ src }) {
  const store = usePlayer();

  return (
    <Container className="video-skin">
      <video src={src} />
      <button onClick={() => store.dispatch('toggle-playback')}>Play</button>
    </Container>
  );
}

Custom provider wrapper

Wrap Player.Provider with additional context using usePlayerContext:
import { usePlayerContext } from '@videojs/react';

function AnalyticsWrapper({ children }) {
  const { store } = usePlayerContext();

  useEffect(() => {
    return store.subscribe(() => {
      if (!store.state.paused) {
        analytics.track('video_play');
      }
    });
  }, [store]);

  return <>{children}</>;
}

Build docs developers (and LLMs) love