Documentation / @zerotal/admin / index / ResourceFormPage
Class: ResourceFormPage
Defined in: admin/src/pages/ResourceFormPage.tsx:75
Base class for Flow pages — reactive server-side components rendered over a WebSocket.
Remarks
A Flow component's state lives on the server. You subclass Component, hold state in
fields, and implement render to return an HtmlNode (authored in .tsx with
jsxImportSource: "@zerotal/flow"). The root element must carry data-flow-root.
Only fields and methods the component opts into are reachable from the browser:
@exposemarks a field as reactive (streamed to the client, writable viaflow:model/$flow.$set) or a method as a callable action (invoked over the socket, e.g.flow:click).@lockedsends a field to the client read-only — it round-trips in the snapshot but the client cannot mutate it (enforced in $set).
Between requests, the component is serialised into an HMAC-signed snapshot and rehydrated on the next round-trip, so tampering with client-held state is rejected. When an action runs, the server re-renders and streams a DOM diff that the browser applies via Alpine's morph — only the changed HTML crosses the wire.
Lifecycle hooks fire in order around each request: onBoot → (onMount on the initial GET / onHydrate on round-trips) → property updates → the action → onUpdate → onRendering → render → onRendered → onDehydrate. Actions may emit side effects — flashes, redirects, events, downloads, client scripts — which are drained after the action and folded into the response frame.
Examples
A counter with an exposed field and an action, bound reactively:
import { Component, expose } from "@zerotal/flow";
export class Counter extends Component {
@expose count = 0;
@expose increment() {
this.count++;
}
override async render() {
return (
<div data-flow-root>
<p>{this.count}</p>
<button flow:click="increment">+</button>
</div>
);
}
}
A form-style component with validation, a flash, and a redirect from an action:
import { Component, expose, locked } from "@zerotal/flow";
export class ProfilePage extends Component {
@locked userId = 0;
@expose name = "";
@expose async save() {
await this.validate({ name: (rule) => rule.required().min(2) });
await User.update(this.userId, { name: this.name });
return this.redirect("/dashboard").withSuccess("Profile saved.");
}
override async render() {
return (
<div data-flow-root>
<input {...this.bind("name")} />
{this.errors.has("name") && <span>{this.errors.name}</span>}
<button flow:click="save">Save</button>
</div>
);
}
}
Extends
Constructors
Constructor
new ResourceFormPage():
ResourceFormPage
Returns
ResourceFormPage
Inherited from
Actions
signal
Get Signature
get signal():
AbortSignal
Defined in: flow/src/Component.ts:447
The AbortSignal for the running @task. Pass it to fetch/an SDK, or check
this.signal.aborted in a loop, for cooperative cancellation. Outside a task it is an
already-inert signal that never aborts, so @task code reads the same regardless.
Returns
AbortSignal
Inherited from
cancelled
Get Signature
get cancelled():
boolean
Defined in: flow/src/Component.ts:455
True when the running @task has been cancelled from the client.
Returns
boolean
Inherited from
flash()
flash(
message,optionsOrLevel?):FlashBuilder
Defined in: flow/src/Component.ts:710
Emit a flash notification to the client.
Returns a FlashBuilder so the toast can be configured fluently. The second argument may also be a level string (back-compat) or a FlashOptions object (for dynamic config):
Parameters
message
string
the toast text.
optionsOrLevel?
"error" | "success" | "warning" | "info" | FlashOptions
a FlashLevel shorthand or a FlashOptions object.
Returns
a FlashBuilder for fluent configuration.
Example
this.flash("Saved"); // success toast
this.flash("Bad input", "error"); // level shorthand
this.flash("Saved", { type: "success", duration }); // options object
this.flash("Post deleted").warning().duration(8000).progressBar();
Inherited from
refresh()
refresh():
Promise<void>
Defined in: flow/src/Component.ts:859
Force onMount() to run again on the CURRENT WebSocket round trip.
Use this to reload external data without requiring a full page reload.
Returns
Promise<void>
Inherited from
client()
client(
script):void
Defined in: flow/src/Component.ts:879
Queue a raw JavaScript expression to be evaluated in the browser after the current action's DOM patch is applied.
The expression runs in the Alpine context of the component root element:
$el, $refs, and other Alpine magic properties are all available.
Multiple calls are batched and executed in order after the single round trip.
Parameters
script
string
Returns
void
Example
this.client(`$refs.titleInput.focus()`);
this.client(`$el.querySelector('.toast').classList.add('visible')`);
Security
Never interpolate unescaped user input into the expression string.
Inherited from
title()
Call Signature
title():
string
Defined in: flow/src/Component.ts:887
Gets the current title value.
Returns
string
Inherited from
Call Signature
title(
value):void
Defined in: flow/src/Component.ts:897
Update document.title in the browser after this action completes.
Parameters
value
string
Returns
void
Example
this.title(`Search: ${this.query}`);
Inherited from
download()
download(
filename,content,mime?):void
Defined in: flow/src/Component.ts:1170
Trigger a browser file download.
content is either text (CSV, JSON, an SVG) or the raw bytes of a binary
file. Text is encoded as UTF-8; bytes are sent exactly as given, which is
what a format like a spreadsheet or a PDF requires — passing those through
a string would re-encode every byte above 127 and corrupt the file.
Parameters
filename
string
the download's suggested file name.
content
string | Uint8Array<ArrayBufferLike>
text, or the file's raw bytes (base64-encoded to travel).
mime?
string = "application/octet-stream"
the MIME type. Defaults to application/octet-stream.
Returns
void
Example
async export() {
const csv = this.buildCsv(this.items);
this.download('export.csv', csv, 'text/csv;charset=utf-8');
}
Inherited from
stream()
stream(
ref,content,opts?):void
Defined in: flow/src/Component.ts:1396
Push content to the client MID-ACTION — before the final patch — into any
element marked flow:stream="ref". Appends by default; pass
{ replace: true } to overwrite instead.
Works only during WebSocket actions (no-op during SSR).
Parameters
ref
string
the flow:stream="ref" target element.
content
string
raw HTML appended (or replacing) inside the target.
opts?
pass { replace: true } to overwrite instead of append.
replace?
boolean
Returns
void
Security
content is injected as raw innerHTML on the client. Never pass
unescaped user input directly — sanitize or escape it first, or use a
trusted HTML sanitizer (e.g. DOMPurify) client-side.
Example
Expose
async generate() { for await (const token of llm.stream(this.prompt)) { this.stream('answer', token); } }
Inherited from
Errors
onError()
onError(
error):Promise<void>
Defined in: flow/src/Component.ts:591
Called when an action throws an unhandled error. Flow catches the error and
still re-renders; override to customise (log, swallow, re-flash). The default
flashes the message. (Livewire exception().)
Parameters
error
Error
the error thrown by the action.
Returns
Promise<void>
Inherited from
Events
dispatch()
dispatch<
K>(name, ...args):void
Defined in: flow/src/Component.ts:1057
Dispatch a named event to all other Flow components on the page.
Components with a matching @on('event-name') decorator will have
their listener method called automatically.
Type Parameters
K
K extends string
Parameters
name
K
args
...K extends never ? EventArgs<FlowEvents[K]> : [Record<string, unknown>]
Returns
void
Example
async save() {
const post = await Post.create(this.form);
this.dispatch('post-created', { id: post.id });
}
Inherited from
dispatchTo()
dispatchTo<
K>(component,name, ...args):void
Defined in: flow/src/Component.ts:1075
Dispatch an event ONLY to components of a given class name (skips all others
listening for the same event). Mirrors Livewire's dispatch()->to(...).
Type Parameters
K
K extends string
Parameters
component
string
name
K
args
...K extends never ? EventArgs<FlowEvents[K]> : [Record<string, unknown>]
Returns
void
Example
this.dispatchTo('Dashboard', 'post-created', { id: post.id });
Inherited from
dispatchSelf()
dispatchSelf<
K>(name, ...args):void
Defined in: flow/src/Component.ts:1094
Dispatch an event only to THIS component (it won't bubble to others).
Mirrors Livewire's dispatch()->self().
Type Parameters
K
K extends string
Parameters
name
K
args
...K extends never ? EventArgs<FlowEvents[K]> : [Record<string, unknown>]
Returns
void
Example
this.dispatchSelf('refresh');
Inherited from
Lifecycle
onMount()
onMount(
ctx?):Promise<void>
Defined in: admin/src/pages/ResourceFormPage.tsx:240
Called ONCE on the initial HTTP GET request.
Never called on subsequent WebSocket round trips (call this.refresh() to force it).
Receives the route HttpContext — the same argument controllers get — so
dynamic-segment pages can read implicitly-bound models off ctx.params:
override async onMount(ctx: HttpContext) {
this.accountId = (ctx.params.account as Account).id;
}
Bound models persist across WebSocket round-trips via Flow synths (store the model on a
@locked/@expose field), so they need not be re-resolved on every action.
Parameters
ctx?
HttpContext<Record<string, string>>
the route HttpContext (initial GET only).
Returns
Promise<void>
Overrides
onUpdate()
onUpdate():
Promise<void>
Defined in: flow/src/Component.ts:510
Called once after the invoked action method completes, just before re-rendering.
Distinct from onUpdated(), which fires per client-driven property change.
Returns
Promise<void>
Inherited from
onBoot()
onBoot(
_ctx?):Promise<void>
Defined in: flow/src/Component.ts:523
Called at the BEGINNING of every request for this component — both the initial
HTTP render and every subsequent WebSocket round-trip — after state is restored
(round-trips) or @url/@session seeded (initial), but before onMount() /
onHydrate(), property updates, and the action. Use for setup that must run on
every request. (Livewire boot().) Receives the route HttpContext — note that on
WebSocket round-trips the URL is the stored route pattern, so raw ctx.params are
only populated on the initial GET; prefer onMount() for reading bound models.
Parameters
_ctx?
HttpContext<Record<string, string>>
Returns
Promise<void>
Inherited from
onHydrate()
onHydrate():
Promise<void>
Defined in: flow/src/Component.ts:533
Called at the beginning of every SUBSEQUENT (WebSocket) request, right after the
component is rebuilt from its snapshot — never on the initial render (use
onMount() for that). Ideal for re-deriving non-persisted/protected state from
restored properties. (Livewire hydrate().)
Returns
Promise<void>
Inherited from
onDehydrate()
onDehydrate():
Promise<void>
Defined in: flow/src/Component.ts:542
Called at the END of every request, just before the component is serialised into
its snapshot. Use to normalise state back into a serialisable shape.
(Livewire dehydrate().)
Returns
Promise<void>
Inherited from
onUpdating()
onUpdating(
_prop,_value,_key?):Promise<void>
Defined in: flow/src/Component.ts:556
Called BEFORE a client-driven property update is applied (a value/checked
input or $flow.$set). Throw to reject the update. Only fires for writable
(@expose) properties. For a single property, define onUpdating<Prop>(value, key?)
— e.g. onUpdatingEmail(). (Livewire updating().)
Parameters
_prop
string
_value
unknown
_key?
string
Returns
Promise<void>
Inherited from
onRendering()
onRendering():
Promise<void>
Defined in: flow/src/Component.ts:573
Called BEFORE render() runs. (Livewire rendering().)
Returns
Promise<void>
Inherited from
onRendered()
onRendered(
_html):Promise<void>
Defined in: flow/src/Component.ts:581
Called AFTER render() produces this component's HTML. (Livewire rendered().)
Parameters
_html
string
Returns
Promise<void>
Inherited from
Navigation & redirects
redirect()
redirect(
url,status?):RedirectFlash
Defined in: flow/src/Component.ts:781
Redirect the client to url after the current action completes.
Returns a builder so a flash can be chained (mirrors the HTTP ResponseBuilder):
Parameters
url
string
Destination URL.
status?
number
Optional HTTP-style status (advisory — the client navigates regardless).
Returns
a RedirectFlash builder for chaining a flash onto the redirect.
Example
this.redirect("/dashboard");
return this.redirect(next || "/", 303).withSuccess("Welcome back.");
return this.redirect("/login").withError("Please sign in.");
Inherited from
redirectRoute()
redirectRoute(
name,params?,status?):RedirectFlash
Defined in: flow/src/Component.ts:820
Redirect to a named route, mirroring Livewire's redirectRoute('profile', ['id' => 1]).
Route params fill :segment placeholders; any extra keys become query-string params.
Parameters
name
string
The route name registered with .name(...).
params?
Record<string, string | number> = {}
Route + query params.
status?
number
Optional HTTP-style status (advisory — the client navigates regardless).
Returns
a RedirectFlash builder for chaining a flash onto the redirect.
Example
return this.redirectRoute("profile", { id: 1 }).withSuccess("Saved.");
this.redirectRoute("posts.show", { slug: "hello", ref: "email" }); // /posts/hello?ref=email
Inherited from
redirectIntended()
redirectIntended(
fallback?,status?):RedirectFlash
Defined in: flow/src/Component.ts:842
Redirect the user back to where they were headed before being intercepted — Livewire's
redirectIntended('/default/url'). Reads (and clears) the intended_url stored in the
session by AuthMiddleware, falling back to fallback when none is stored or the stored
URL is cross-origin (open-redirect guard).
Parameters
fallback?
string = "/"
URL to use when no intended URL is available. Defaults to /.
status?
number
Optional HTTP-style status (advisory — the client navigates regardless).
Returns
a RedirectFlash builder for chaining a flash onto the redirect.
Example
if (await Auth.attempt(creds)) return this.redirectIntended("/dashboard");
Inherited from
currentUrl()
currentUrl(
_options?):string
Defined in: flow/src/Component.ts:1133
Build a URL from the current one with merged query params — client-only. Use it in a
JSX expression: href={this.currentUrl({ query: this.q })}, class={this.currentUrl() === "/" ? "on" : ""},
or {this.currentUrl(...)}. The compiler rewrites this.currentUrl → $flow.currentUrl
so it runs on the client. It never runs on the server — hitting this throw means the call
reached server code (e.g. a page the compiler couldn't statically compile, or a server action).
Parameters
_options?
CurrentUrlOptions
Returns
string
Throws
when executed on the server (it is meant to be compiled to $flow.currentUrl).
Inherited from
navigateCurrent()
navigateCurrent(
_options?):Promise<void>
Defined in: flow/src/Component.ts:1145
Build the URL as currentUrl does, then SPA-navigate to it — client-only. Use it in a
client handler: onClick={() => this.navigateCurrent({ query: { page: 2 } })}. The compiler
rewrites it to $flow.navigateCurrent. To navigate from server code, return a redirect().
Parameters
_options?
CurrentUrlOptions
Returns
Promise<void>
Throws
when executed on the server (it is meant to be compiled to $flow.navigateCurrent).
Inherited from
Other
head
Get Signature
get
statichead():string
Defined in: admin/src/pages/ResourceFormPage.tsx:160
Stylesheet + theme tokens for the panel owning this request.
Returns
string
slug
slug:
string=""
Defined in: admin/src/pages/ResourceFormPage.tsx:76
mode
mode:
FieldMode="create"
Defined in: admin/src/pages/ResourceFormPage.tsx:77
recordId
recordId:
string=""
Defined in: admin/src/pages/ResourceFormPage.tsx:78
panelId
panelId:
string=DEFAULT_PANEL_ID
Defined in: admin/src/pages/ResourceFormPage.tsx:84
Which panel is being served. Locked rather than derived, so the WebSocket round-trips that drive this page — which carry no URL — keep resolving the same resource, base path and shell as the initial render.
parentId
parentId:
string=""
Defined in: admin/src/pages/ResourceFormPage.tsx:86
The parent record's id, for a resource nested under another.
loadedVersion
loadedVersion:
string=""
Defined in: admin/src/pages/ResourceFormPage.tsx:92
The record's version as it was when this form loaded, for a resource using
optimisticLock. Locked, so a WebSocket save compares against what was
actually rendered rather than whatever the client claims.
formLocale
formLocale:
string=""
Defined in: admin/src/pages/ResourceFormPage.tsx:94
The locale being edited, for a resource with translatable fields.
translations
translations:
Record<string,Record<string,unknown>> ={}
Defined in: admin/src/pages/ResourceFormPage.tsx:102
Every locale's value for each translatable field, as the record held them.
Kept because the form only ever shows one locale: without the rest, saving
an English edit would write { en: "…" } over a record that also had French
and German. Locked so the client cannot rewrite the locales it isn't editing.
form
form:
Form&Record<string,unknown>
Defined in: admin/src/pages/ResourceFormPage.tsx:109
switchLocale()
switchLocale(
code):void
Defined in: admin/src/pages/ResourceFormPage.tsx:124
Switch the locale being edited.
The current locale's text is banked into the translation map first, so switching tabs mid-edit does not throw the work away, then the new locale's text is loaded into the same fields.
Parameters
code
unknown
Returns
void
layout()
layout(
page):Promise<HtmlNode>
Defined in: admin/src/pages/ResourceFormPage.tsx:155
The shell. Rendered through the instance hook rather than static layout,
because one class serves every panel and the shell differs per panel — the
layout marks its own identity so the client still swaps only the content
slot when navigating within a panel.
Parameters
page
Returns
Promise<HtmlNode>
Overrides
setField()
setField(
key,value):void
Defined in: admin/src/pages/ResourceFormPage.tsx:302
Set a single field's value from the server (radio / native-control fallbacks).
Parameters
key
unknown
value
unknown
Returns
void
toggleArrayValue()
toggleArrayValue(
key,value):void
Defined in: admin/src/pages/ResourceFormPage.tsx:307
Toggle a value in an array-valued field (checkbox list / multiple select).
Parameters
key
unknown
value
unknown
Returns
void
tagDraft
tagDraft:
Record<string,string> ={}
Defined in: admin/src/pages/ResourceFormPage.tsx:315
Draft text for each tags input, keyed by field.
addTag()
addTag(
key):void
Defined in: admin/src/pages/ResourceFormPage.tsx:318
Commit the current tag draft into a tags field's array.
Parameters
key
unknown
Returns
void
removeTag()
removeTag(
key,index):void
Defined in: admin/src/pages/ResourceFormPage.tsx:329
Remove a tag by index.
Parameters
key
unknown
index
unknown
Returns
void
pickingFor
pickingFor:
string=""
Defined in: admin/src/pages/ResourceFormPage.tsx:338
The field a media picker is open for, or empty when it is closed.
pickerSearch
pickerSearch:
string=""
Defined in: admin/src/pages/ResourceFormPage.tsx:339
mediaUpload
mediaUpload:
unknown=null
Defined in: admin/src/pages/ResourceFormPage.tsx:348
A file chosen from inside the picker.
Held on the page rather than on the form, because the form's exposed properties are generated from the resource's declared fields — an extra key on it is not part of the snapshot, so the upload's reference would be dropped on the way back and the file would silently never arrive.
openMediaPicker()
openMediaPicker(
key):void
Defined in: admin/src/pages/ResourceFormPage.tsx:430
Parameters
key
unknown
Returns
void
closeMediaPicker()
closeMediaPicker():
void
Defined in: admin/src/pages/ResourceFormPage.tsx:435
Returns
void
chooseMedia()
chooseMedia(
path):void
Defined in: admin/src/pages/ResourceFormPage.tsx:440
Choose a library file for the field the picker was opened from.
Parameters
path
unknown
Returns
void
onUpdated()
onUpdated(
prop,_value):Promise<void>
Defined in: admin/src/pages/ResourceFormPage.tsx:456
Store the file once its bytes have actually arrived.
Driven by the property update rather than the input's change event, and
the difference is the whole bug: a bound file input starts an HTTP upload on
change and only sets the signed reference when that finishes. An action
fired from change therefore ran while the property was still empty, found
nothing to store, and returned silently — the file picker appeared to do
nothing at all.
Parameters
prop
string
_value
unknown
Returns
Promise<void>
Overrides
uploadToLibrary()
uploadToLibrary():
Promise<void>
Defined in: admin/src/pages/ResourceFormPage.tsx:461
Upload straight into the library from the picker, and select the result.
Returns
Promise<void>
removeFile()
removeFile(
key):void
Defined in: admin/src/pages/ResourceFormPage.tsx:481
Parameters
key
unknown
Returns
void
repeaterDraft
repeaterDraft:
Record<string,unknown> ={}
Defined in: admin/src/pages/ResourceFormPage.tsx:493
Flat per-sub-input draft for repeater/builder rows.
addRepeaterItem()
addRepeaterItem(
key):void
Defined in: admin/src/pages/ResourceFormPage.tsx:517
Append an empty repeater row (sub-fields seeded to their defaults).
Parameters
key
unknown
Returns
void
addBuilderBlock()
addBuilderBlock(
key,blockName):void
Defined in: admin/src/pages/ResourceFormPage.tsx:533
Append a builder block of the given type (its fields seeded to defaults).
Parameters
key
unknown
blockName
unknown
Returns
void
removeRepeaterItem()
removeRepeaterItem(
key,rowId):void
Defined in: admin/src/pages/ResourceFormPage.tsx:551
Remove a repeater/builder row by id (and drop its drafts).
Parameters
key
unknown
rowId
unknown
Returns
void
moveRepeaterItem()
moveRepeaterItem(
key,rowId,dir):void
Defined in: admin/src/pages/ResourceFormPage.tsx:564
Move a repeater/builder row up (-1) or down (+1).
Parameters
key
unknown
rowId
unknown
dir
unknown
Returns
void
fieldChanged()
fieldChanged(
key):void
Defined in: admin/src/pages/ResourceFormPage.tsx:607
Run a live field's afterStateUpdated hook and merge its patch into the form.
Parameters
key
unknown
Returns
void
wizardStepIndex
wizardStepIndex:
number=0
Defined in: admin/src/pages/ResourceFormPage.tsx:622
Current wizard step index.
nextStep()
nextStep():
void
Defined in: admin/src/pages/ResourceFormPage.tsx:649
Validate the current step's fields, then advance.
Returns
void
prevStep()
prevStep():
void
Defined in: admin/src/pages/ResourceFormPage.tsx:666
Returns
void
wizardSubmit()
wizardSubmit():
Promise<void>
Defined in: admin/src/pages/ResourceFormPage.tsx:671
Form submit inside a wizard: advance a step, or save on the last one.
Returns
Promise<void>
save()
save():
Promise<void>
Defined in: admin/src/pages/ResourceFormPage.tsx:678
Returns
Promise<void>
Rendering
render()
render():
Promise<HtmlNode>
Defined in: admin/src/pages/ResourceFormPage.tsx:1679
Return the JSX that represents this page.
Must include a single root element with data-flow-root.
Returns
Promise<HtmlNode>
the rendered HtmlNode tree for this component.
Overrides
placeholder()
placeholder():
HtmlNode
Defined in: flow/src/Component.ts:617
Return the placeholder HTML shown while a lazy/deferred component loads.
Override this in child components that use { lazy: true } or { defer: true }.
Returns
Example
override placeholder() {
return <div class="skeleton animate-pulse h-24 w-full rounded-lg" />;
}
Inherited from
slot()
slot(
name?):HtmlNode
Defined in: flow/src/Component.ts:677
Return the HTML the parent passed for a named slot, for placing inside this
component's render(). Call with no argument for the default slot (the child's
plain children), or a name for a named slot (slots={{ header: … }} on the parent).
Returns an empty node when the slot wasn't provided, so {this.slot("footer")}
is safe to leave in the template unconditionally.
Slot content is rendered in the PARENT's scope and carried in this component's
snapshot, so it survives the child's own round-trips. Use hasSlot() to branch
on whether a slot was supplied (e.g. to omit a wrapping <header> entirely).
Parameters
name?
string = "default"
the slot name; omit for the default slot.
Returns
the slot's HTML, or an empty node when the slot was not provided.
Example
override async render() {
return (
<div class="card">
{this.hasSlot("header") && <header>{this.slot("header")}</header>}
<div class="body">{this.slot()}</div>
{this.hasSlot("footer") && <footer>{this.slot("footer")}</footer>}
</div>
);
}
Inherited from
hasSlot()
hasSlot(
name?):boolean
Defined in: flow/src/Component.ts:685
True when the parent supplied (non-empty) content for the given slot.
Parameters
name?
string = "default"
Returns
boolean
Inherited from
child()
child<
C>(ChildClass,opts?):Promise<HtmlNode>
Defined in: flow/src/Component.ts:1233
Embed another Component as a nested component with its own isolated state, its own WebSocket update cycle, and its own snapshot.
Children are islands: a parent re-render does NOT re-render existing
children (their DOM and state are preserved on the client), and a child
update never touches the parent. Use key when embedding the same
component class multiple times (e.g. in a loop).
props are assigned to the child instance before onMount() runs.
Pass lazy: true to use IntersectionObserver — onMount() is deferred
until the placeholder enters the viewport.
Pass defer: true to load immediately after page paint (no intersection check).
Type Parameters
C
C extends Component
Parameters
ChildClass
() => C
the child Component class to embed.
opts?
key disambiguates repeated instances; props seed the child before
onMount(); lazy/defer render a placeholder first; slots pass named
slot HTML.
key?
string | number
props?
Partial<C>
lazy?
boolean
defer?
boolean
slots?
Record<string, string>
Named slot HTML (name → html, default slot keyed "default"), rendered by the parent.
Returns
Promise<HtmlNode>
the child's rendered HtmlNode (root or placeholder).
Example
override async render() {
return <div>
<h1>Dashboard</h1>
<StatsWidget />
<CounterWidget key="a" step={5} />
<SlowWidget lazy />
</div>;
}
Inherited from
State & exposure
durable?
staticoptionaldurable?:boolean| {ttl?:string;scope?:"session"|"user"; }
Defined in: flow/src/Component.ts:467
Opt into durable/resumable snapshots: static durable = true (or { ttl, scope }).
The signed snapshot is persisted server-side after every request, keyed by user (or
session) + route, and restored on a fresh GET so the user resumes exactly. See
clearDurable to drop the stored state on flow completion.
Inherited from
clearDurable()
clearDurable():
void
Defined in: flow/src/Component.ts:479
Forget this component's durable snapshot at the end of the current request — call it when a
durable flow completes (a wizard finished, a form submitted) so the next visit starts fresh
instead of resuming the finished state. No-op unless the component opted into static durable.
Returns
void
Inherited from
bind()
bind(
key):Record<string,unknown>
Defined in: flow/src/Component.ts:1192
Emit the HTML attributes needed for flow:model two-way binding.
Parameters
key
string
the @expose property to two-way bind.
Returns
Record<string, unknown>
the flow:model + value attributes to spread onto an input.
Example
<input {...this.bind('name')} />
// → <input flow:model="name" value="Alice" />
Inherited from
Validation
errors
Get Signature
get errors():
ErrorsProxy
Defined in: flow/src/Component.ts:384
Typed access to this component's validation error bag.
this.errors.has("field")→booleanthis.errors.field→ an ErrorField forerror={this.errors.field}this.errors.add("field", "message")→ add an error manuallythis.errors.add({ field: "message" })→ add several at oncethis.errors.clear(field?)→ clear one field, or all
Returns
Inherited from
validate()
validate(
rulesOrForm?):Promise<void>
Defined in: flow/src/Component.ts:937
Validate page properties against rules. If validation fails, errors are
stored and a ValidationError is thrown (caught by the framework, which
re-renders the page with $errors populated client-side).
Pass explicit rules or omit to use @validate decorator rules.
Error persistence: validation errors survive across actions and are
re-sent on every patch until the next validate() call clears them (on
success) or resetValidation() is called explicitly. If you want errors
cleared at the start of every action, call this.resetValidation() before
the new validate() call.
Parameters
rulesOrForm?
ValidationRules | { __isFlowForm: true; _validateToErrors: Record<string, string[]>; }
explicit per-field rules, a Form instance to validate, or
omit to use the component's @validate decorator rules.
Returns
Promise<void>
Example
async save() {
this.validate({
email: (rule) => rule.required().email(),
password: (rule) => rule.required().min(8),
});
// reaches here only if valid
}
Throws
when validation fails — the framework catches it and re-renders
with this.errors populated.
Inherited from
addError()
addError(
field,message):void
Defined in: flow/src/Component.ts:1020
Manually add a validation error for a field.
Parameters
field
string
message
string
Returns
void
Example
this.addError('email', 'That email is already taken.');
Inherited from
resetValidation()
resetValidation(
field?):void
Defined in: flow/src/Component.ts:1034
Clear validation errors — all fields, or just the specified field.
Parameters
field?
string
Returns
void
Example
this.resetValidation(); // clear all
this.resetValidation('email'); // clear email only