# React integration Install the dedicated adapter: ```sh npm install @pixel-point/aval-react@1.0.0 ``` The package owns custom-element registration, source markup, native event listeners, and React lifecycle integration. Its root is SSR-safe. ## Basic usage ```tsx import { useAval } from "@pixel-point/aval-react"; const FAVORITE_SOURCES = { av1: "/motion/favorite/av1.avl", vp9: "/motion/favorite/vp9.avl", h265: "/motion/favorite/h265.avl", h264: "/motion/favorite/h264.avl" } as const; export function FavoriteMotion({ state }: { state: string }) { const { aval, AvalComponent } = useAval({ sources: FAVORITE_SOURCES, state, autoplay: true, autoBind: true, onError: ({ fatal, failure }) => { if (fatal) reportPlaybackFailure(failure.code); } }); return ( <> {aval.lastError?.fatal && } ); } ``` `sources` requires at least one codec URL. Values are URL strings; there is no React JSON manifest, bundle-version, or integrity-descriptor API. Browser selection always follows AV1, VP9, H.265, then H.264 regardless of object key order. Changing a URL updates the existing player in place. `AvalComponent` is bound to its `useAval()` call and has stable identity. Mount one instance of that returned component at a time. It accepts ordinary HTML, ARIA, `className`, and `style` props plus `width`, `height`, and `bindTo`. The adapter exclusively owns its direct `` children, so child content and `dangerouslySetInnerHTML` are not accepted. ## State and authored events The `state` option is application-owned declarative intent. AVAL does not write runtime state back into it. Do not mirror every `visualState` change into the option. ```tsx const { aval, AvalComponent } = useAval({ sources: CHECKOUT_SOURCES, state: "idle" }); return ( <> requested: {aval.requestedState ?? "none"}; visual:{" "} {aval.visualState ?? "none"} ); ``` `requestedState` changes when the graph accepts an intent. `visualState` changes when destination pixels commit. `setState()` resolves at that visual commit. A newer different request rejects an older pending request with `AbortError`. Authored events are synchronous: ```ts const accepted = aval.send("retry.requested"); ``` `false` means the event was not currently routable or the runtime was not ready. ## Playback and automatic bindings `autoplay: true` maps to visibility-aware playback; `false` starts in manual mode. Use `aval.pause()` and `await aval.play()` to control manual playback. `autoBind: true` enables authored pointer, focus, activation, and visibility bindings. They target the motion element by default. Associate them with a semantic control through `bindTo`: ```tsx const buttonRef = useRef(null); const { AvalComponent } = useAval({ sources: FAVORITE_SOURCES, autoBind: true }); return ( ); ``` Set `autoBind: false` when application code sends all state and event intent. ## Reactive updates, SSR, and cleanup `aval` exposes `mounted`, readiness, requested and visual state, transition status, pause and effective-visibility state, authored state/event names, and the latest normalized error. React rerenders only for semantic snapshot changes, never for decoded frames. Server rendering emits inert `` and direct `` children. On the client, the adapter installs the direct error listener before defining the custom element. React Strict Mode cleanup removes adapter listeners and subscriptions but never terminally disposes the element; DOM disconnection remains AVAL's resource-retirement authority. `staticReady` is a successful reduced-motion, visibility, or decoder-admission outcome, not a fatal fallback signal. AVAL renders no alternate UI and never hides itself. Applications retain ownership of sibling fallback content.