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

53 lines
1.8 KiB
Markdown

---
status: implemented
date: 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.