4.6 KiB
Component Patterns
Patterns for Video.js web components. For ReactiveElement fundamentals (lifecycle, properties, controllers), see videojs-element.md.
Package Requirements
import { ReactiveElement } from '@videojs/element';
import { ContextConsumer, ContextProvider } from '@videojs/element/context';
- Use
@videojs/elementfor the base class and types - Use
@videojs/element/contextfor context (re-exports@lit/context) - Never import from
litor@lit/reactive-element
Platform Bindings
- Store HTML bindings:
@videojs/store/html - Main web component library:
@videojs/html
Component Types
Skins (Container Elements)
- Extend
ReactiveElement - May use shadow DOM for style encapsulation
- Provide store to descendants via context
- Register with
customElements.define()
Primitives (Control Elements)
- Extend
ReactiveElement - No shadow DOM — style via light DOM
- No slots
- No render() — manipulate host element directly
- Controllers provide all behavior
Controllers
Controllers are the primary composability mechanism. Use controllers, not hooks or behavior mixins.
All store-related controllers live in @videojs/store/html. See that package for available controllers and their APIs.
Controller Pattern
class MyElement extends ReactiveElement {
#store = new StoreController(this, context);
}
Architecture
- Accept
StoreSource<Store>— either direct store OR context StoreAccessorresolves source internally- Register via
host.addController(this) - Lifecycle:
hostConnected(),hostDisconnected()
StoreAccessor
Internal utility that resolves a store from either a direct instance or context. This enables controllers to accept a StoreSource<Store> parameter — users can pass either:
- Direct store — For testing or when store is already available
- Context — For production use where store is provided by an ancestor
// Direct store — value available immediately
const store = new StoreController(this, store);
// Context — value available after context resolves
const store = new StoreController(this, context);
Controllers handle both cases transparently. The StoreAccessor:
- Returns store immediately if passed directly
- Waits for context resolution if passed a context
- Fires
onAvailablecallback when store becomes available (for subscription setup)
Host Type Pattern
Always export an explicit host type for controllers and mixins:
export type StoreControllerHost = ReactiveControllerHost & HTMLElement;
export type ProviderMixinHost = ReactiveElement & EventTarget;
- Never use bare
ReactiveControllerHost - Allows future extension without breaking consumers
- Self-documents required host capabilities
Mixins
Mixins are for store provision only, not behavior. Behavior goes in controllers.
Store Mixins
createStore() returns mixins for different use cases:
const { StoreMixin, ProviderMixin, ContainerMixin } = createStore({
features: [playbackFeature],
});
// StoreMixin: provides store AND auto-attaches slotted media
class MyPlayer extends StoreMixin(ReactiveElement) {
// Store provided to all descendants, media auto-attached
}
// ProviderMixin: provides store only (no auto-attach)
class MyProvider extends ProviderMixin(ReactiveElement) {
// Store provided to all descendants
}
// ContainerMixin: consumes store from context, auto-attaches media
class MyControls extends ContainerMixin(ReactiveElement) {
// Inherits store from parent provider
}
- Creates store on first access (lazy)
- Provides via Context Protocol (
@lit/context) - Destroys store on disconnect (if owned)
Context Protocol
ContextProvider— skin/root provides store to descendantsContextConsumer— controllers consume store via context- Context passed as
StoreSourceto controller constructors
// Provider (in skin)
#provider = new ContextProvider(this, { context, initialValue: this.store });
// Consumer (in controller)
#consumer = new ContextConsumer(host, { context, subscribe: false });
Element Registration
Use the standard custom elements registry:
customElements.define('vjs-play-button', PlayButtonElement);
For elements that need a store mixin:
customElements.define('vjs-player', StoreMixin(PlayerElement));
See Also
@videojs/store/html— Controller and mixin implementations@videojs/html— Web component library- react.md — React-specific patterns (parallel reference)