Skip to main content
StoreController is a reactive controller for accessing store state and actions in custom elements. It accepts a store instance or a context and resolves the store automatically.
  • Without a selector — returns the store instance directly. Does not subscribe to changes. Use this to access store actions.
  • With a selector — returns the selected value and subscribes to changes. Triggers a host update when the selected value changes (shallow equality).

Signature

import { StoreController } from '@videojs/store/html';

class StoreController<Store extends AnyStore, Result = Store>
  implements ReactiveController

Constructor

new StoreController(host, source)
host
StoreControllerHost
required
The host element (ReactiveControllerHost & HTMLElement) that owns this controller. Typically this inside a custom element class.
source
StoreSource<Store>
required
A store instance or a context object. When a context is provided, the store is resolved from the nearest provider in the DOM tree.

Properties

value
Result
The current value:
  • Without a selector: the store instance.
  • With a selector: the return value of the selector applied to the current state.
Throws if the store is not yet available (e.g., the host is disconnected and no store was resolved).

Usage

Accessing actions (without selector)

Without a selector, StoreController returns the store and does not subscribe to updates. Use this to dispatch actions imperatively.
import { StoreController } from '@videojs/store/html';

class VolumeControl extends HTMLElement {
  readonly #store = new StoreController(this, storeSource);

  connectedCallback() {
    this.addEventListener('click', this.#handleClick);
  }

  #handleClick = () => {
    this.#store.value.setVolume(0.5);
  };
}

customElements.define('volume-control', VolumeControl);

Subscribing to state (with selector)

With a selector, StoreController subscribes to the store and triggers a host update whenever the selected value changes.
import { StoreController } from '@videojs/store/html';

class PlayButton extends HTMLElement {
  readonly #playback = new StoreController(this, storeSource, selectPlayback);

  render() {
    const playback = this.#playback.value;
    this.textContent = playback.paused ? 'Play' : 'Pause';
  }

  connectedCallback() {
    this.addEventListener('click', () => this.#playback.value.toggle());
  }
}

customElements.define('play-button', PlayButton);

StoreController vs PlayerController vs SnapshotController

StoreControllerPlayerControllerSnapshotController
InputAny store or contextPlayer store contextState<T> container
Typed toGeneric storePlayer featuresRaw state
Resolves storeYes (from context)Yes (from player context)No
Use caseGeneral-purpose store accessPlayer UI elementsLow-level state subscription
PlayerController is a typed wrapper around StoreController scoped to the player store. For player UI, prefer PlayerController. Use StoreController when working with a custom store outside the player system. When you pass a selector, StoreController internally creates a SnapshotController on store.$state. Without a selector, no subscription is created.
StoreController.value throws if the store is not available. Without a selector, guard access with a conditional or call .value only inside event handlers where the element is guaranteed to be connected.

Build docs developers (and LLMs) love