Files
v10/internal/design/element/reactive-element-lit-compat.md
T

1.8 KiB

status, date
status date
implemented 2026-03-05

Destroy Lifecycle: DestroyMixin

Decision

The deferred destruction lifecycle is implemented as a composable mixin (DestroyMixin) exported from @videojs/element, rather than being added directly to ReactiveElement.

ReactiveElement stays structurally compatible with Lit's ReactiveElement.

Architecture

@videojs/utils/dom   → deferFrames() composable utility
@videojs/element     → DestroyMixin(HTMLElement) — generic, works with any base
@videojs/html        → MediaElement = DestroyMixin(ReactiveElement) + hostDestroyed()
@videojs/core        → HlsCustomMedia = DestroyMixin(HTMLElement) via CustomMediaMixin

DestroyMixin

Adds destroyed, destroy(), destroyCallback(), deferred 2-rAF scheduling on disconnect, cancel on reconnect, and keep-alive attribute support. Works with any HTMLElement subclass.

MediaElement

Composes DestroyMixin(ReactiveElement) and bridges destroyCallback() to hostDestroyed() on reactive controllers. Also guards performUpdate() when destroyed.

HlsCustomMedia

Uses DestroyMixin(HTMLElement) as the base for CustomMediaMixin. The DelegateMedia class (from DelegateMixin) overrides destroyCallback() to call this.#delegate.destroy?.(), which destroys the HLS engine.

Why a Mixin

  • ReactiveElement stays Lit-compatible (no added public surface)
  • Works with HTMLElement directly (no ReactiveElement required for custom media elements)
  • Composable — any element can opt in

Alternatives Considered

  • Put everything on ReactiveElement — Simpler (direct #controllers access), but breaks Lit structural compat. Rejected.
  • Separate MediaElement class without mixin — Doesn't compose with CustomMediaMixin(HTMLElement) for custom media elements. Rejected.