Interface: CreatePlayUIOptions
API / @xmachines/play-dom / CreatePlayUIOptions
Defined in: packages/play-dom/src/types.ts:152
The options of createPlayUI(), the complete DOM factory.
This type extends UIProviderOptions, which gives functions,
directives, validationFunctions, navigate, and onRenderError. The factory
holds all of them from the moment of its creation, and it gives them to
PlayRenderer on every mount() call.
It also takes PlayDomOptions.onError, which the factory forwards without a
change: PlayRenderer owns it, and it receives every failure of a rebuild that the
renderer contains. Read that entry for the complete rule. fallback below says what
the factory adds to PlayDomOptions.fallback.
This type is parallel to the props of PlayUIProvider in the framework renderers.
See
createPlayUI
Extends
UIProviderOptions.Pick<PlayDomOptions,"onError">
Properties
| Property | Type | Description | Inherited from | Defined in |
|---|---|---|---|---|
directives? | DirectiveDefinition<ZodType<unknown, unknown, $ZodTypeInternals<unknown, unknown>>>[] | Custom directives — user-defined $-prefixed dynamic values that extend the spec expression language (e.g. { $format: "currency", value: ... }). Each entry is a DirectiveDefinition built with defineDirective from @xmachines/json-render-core. The array is converted to a DirectiveRegistry once per render pass and forwarded to resolveElementProps via PropResolutionContext.directives. Built-in expressions ($state, $cond, etc.) always take precedence over custom directives. Mirrors the directives prop on JSONUIProvider / JsonUIProvider introduced in Json-render 0.19. Example import { defineDirective, resolvePropValue } from "@xmachines/json-render-core"; import { z } from "zod"; const formatDirective = defineDirective({ name: "$format", description: "Locale-aware number formatting.", schema: z.object({ $format: z.enum(["number", "currency"]), value: z.unknown() }), resolve(value, ctx) { const resolved = resolvePropValue(value.value, ctx); return new Intl.NumberFormat().format(resolved as number); }, }); renderSpec(spec, store, registry, { directives: [formatDirective] }); | UIProviderOptions.directives | - |
fallback? | HTMLElement | (() => HTMLElement) | null | The optional fallback content — see PlayDomOptions.fallback for what the renderer does with it. The factory shows it for every null view, and after a failure of a rebuild that the renderer contains. Give a FUNCTION when the factory mounts more than one time. ONE factory serves every mount() call, and appendChild MOVES a node. A single element therefore passes from one container to the next on every null view, and the container that loses it goes empty without a notice. A function runs one time for each mount, so every renderer owns its own element: const mount = createPlayUI(registryResult, { fallback: () => { const element = document.createElement("p"); element.textContent = "Loading…"; return element; }, }); An element stays correct for a factory that mounts one time. | - | packages/play-dom/src/types.ts:176 |
functions? | Record<string, ComputedFunction> | Named compute functions for { $computed: "name", args: {...} } prop expressions. Each function receives the resolved args object and returns the computed value. Forwarded directly to resolveElementProps via PropResolutionContext.functions, matching the FunctionsContext provider in the framework renderers. Without this option, $computed expressions resolve to undefined (no throw). Example renderSpec(spec, store, registry, { functions: { fullName: (args) => ${args.first} ${args.last}, formatCurrency: (args) => new Intl.NumberFormat().format(args.amount as number), }, }); Mirrors the functions prop on JSONUIProvider / JsonUIProvider. | UIProviderOptions.functions | - |
navigate? | (path) => void | Programmatic navigation function. Called automatically when an action binding resolves with onSuccess: { navigate: "/path" }. The resolved path string is passed as the sole argument. Mirrors the navigate prop in ActionProvider from the framework renderers, where it is captured in the execute() closure. Also available to component implementations directly via ctx.ctx.navigate for cases where navigation needs to be triggered outside of an action binding. Example import { useNavigate } from "my-router"; const navigate = useNavigate(); renderSpec(spec, store, registry, { navigate }); Spec binding that triggers navigation: { "on": { "click": { "action": "doSomething", "onSuccess": { "navigate": "/dashboard" } } } } | UIProviderOptions.navigate | - |
onConfirm? | ConfirmHandler | Confirmation hook for actions that declare confirm in their binding. Consulted by emit() before executing a confirm-gated action. Return (or resolve) true to execute, false to skip. Without this handler, confirm-gated actions are skipped with a console.warn — they never execute unconfirmed. See ConfirmHandler for the full contract. This is the headless equivalent of the pendingConfirmation / confirmAction() / cancelAction() flow in the framework adapters. | UIProviderOptions.onConfirm | - |
onError? | (error, reset) => void | The optional handler of a failure of a complete rebuild of the view. This option is NOT the same as onRenderError, which UIProviderOptions gives: the inner renderer routes a render error of one component, and a rejection of one action handler, to onRenderError. It contains each of them per element, and the rebuild continues. onError receives the failure of the complete rebuild that no per-element boundary caught. The renderer CONTAINS a rebuild that throws, with this option and without it: it resets the state of the failed rebuild, so that the next emission makes a complete render again, and it clears the container. connect() renders the first view synchronously, so a bad initial view makes connect() throw no more. A WRITE of the store takes the same path. The renderer resolves the props of every element that the write touched, so a $computed function that throws on the new state aborts that render too. The renderer contains such a failure as well, and the action handler that wrote the state receives no exception. This option says WHERE the report goes. Without it, the renderer writes the contained failure to console.error. A handler that THROWS reaches no caller: the renderer contains that throw too, and it writes the throw to console.error. A host that must escalate a failure raises it from a task of its own — queueMicrotask(() => { throw error; }) — which reaches the global handler of the page and leaves the containment whole. The five renderers hold this one rule. The second parameter is the RESET, for a retry that the host starts — a “Retry” button of its own. It renders the view that the actor holds at the MOMENT OF THE CALL, so a host that keeps the callback cannot rewind the screen to the view that failed. A reset that the host calls from inside this handler does nothing, because no input changed between the two attempts, and a reset after disconnect() does nothing. A reset belongs to ONE connection. connect() starts a connection, and the reset of a report of an older connection does nothing. A host that calls connect() again from inside this handler abandons the connection that reported. The “Retry” button of that report must not render into the connection that took its place. Call the reset of the newest report. This option matches the onError prop of the framework renderer providers, and the five renderers hold the same three rules for the reset. | PlayDomOptions.onError | packages/play-dom/src/types.ts:100 |
onRenderError? | RenderErrorHandler | Unified error handler for component render errors and action handler rejections. Matches RenderErrorHandler = (error: unknown, name: string) => void. Invoked for three distinct error classes: - (error, elementType) — when a component renderer throws synchronously during renderSpec - (error, actionName) — when an action handler rejects during emit() (on-event path) - (error, actionName) — when an action handler rejects during a watch binding callback When provided, suppresses the console.error fallback for all three error types. Forwarded into renderSpec as the onRenderError parameter and into DomRenderContext.onRenderError so both emit() and watch handlers route their errors through the same channel as component render errors. Example renderSpec(spec, store, registry, { onRenderError: (err, name) => { myErrorReporter.capture(err, { context: name }); }, }); | UIProviderOptions.onRenderError | - |
validationFunctions? | Record<string, (value, args?) => boolean> | Custom validation functions for inline field validation. Each function receives (value, args?) and returns true (valid) or false (invalid). Functions are available to component implementations via ctx.ctx.validationFunctions and should be passed as customFunctions to runValidationCheck / runValidation from @xmachines/json-render-core. Mirrors customFunctions in ValidationProvider from the framework renderers. The DOM renderer has no automatic ValidationProvider tree — validation must be invoked explicitly by component implementations. Example import { runValidationCheck } from "@xmachines/json-render-core"; renderSpec(spec, store, registry, { validationFunctions: { isEven: (value) => typeof value === "number" && value % 2 === 0, phoneNumber: (value) => /^\+?[\d\s\-()]{7,}$/.test(String(value)), }, }); // Inside a ComponentFn: const MyField: ComponentFn<typeof catalog, "MyField"> = ({ ctx }) => { const result = runValidationCheck( { type: "isEven", message: "must be even" }, { value: someValue, stateModel: {}, customFunctions: ctx.ctx.validationFunctions }, ); // result.valid, result.message }; | UIProviderOptions.validationFunctions | - |