EngineForms (EF)
Schema types: "form", "input", "textarea", "checkbox", and "label".
EngineForms are native form elements with engine styling and named-handler
resolution. Field binding is currently driven by name, not by
cprop.bind.
Submit flow
input/textarea/checkbox props.name
↓
data-engine-bind="name"
↓
EngineForm collects bound values on submit
↓
named createPage handler receives (values, submitEvent)
↓
your handler may pass values to EngineAPIResolverEngineAPIResolver does not walk the form DOM itself.
Form
{
type: "form",
props: {
onSubmit: "handleLogin",
noValidate: false,
},
children: [/* fields */],
}Prop | Type | Notes |
|---|---|---|
|
| Named handler from |
|
| Named reset handler |
| `"get" \ | "post"` |
|
| Native action URL |
|
| Native validation control |
|
| Native autocomplete |
|
| Native encoding type |
When a named submit handler exists and no native action is supplied,
EngineForm prevents the browser's default navigation and calls:
handler(values, event)If an action is present, the named handler may still observe the submission,
but EngineForm does not automatically cancel the native action.
Input / Textarea
name is both the native form field name and EngineForms binding key.
{
type: "input",
props: {
id: "email",
name: "email",
type: "email",
required: true,
onChange: "emailChanged",
},
}A named onChange handler receives:
handler(currentValue, changeEvent)File inputs contribute a File for a single selection or File[] when
multiple is enabled. Disabled fields are skipped.
Checkbox values
Checkbox binding currently produces:
- checked → the checkbox
value, or"on"when no value was supplied; - unchecked →
"off".
Repeated fields with the same binding name are accumulated into an array.
Label
{ type: "label", props: { forInput: "email", children: "Email" } }forInput: "email" maps to htmlFor="for-email". Use a matching input id:
{ type: "input", props: { id: "for-email", name: "email" } }You may use htmlFor directly instead.
EngineAPI example
export default createPage({
schema: LoginSchema,
handlers: {
async handleLogin(values: Record<string, unknown>) {
const resolver = new EngineAPIResolver({
endpoint: "https://api.example.com/login",
method: "POST",
});
const response = await resolver.resolveRequest({ formData: values });
// handle response
},
},
});For binary values EngineAPIResolver creates native FormData and lets fetch
set the multipart boundary. For non-binary object values it sends JSON by
default.
Current binding API
Do not rely on old docs/examples that say cprop.bind automatically talks to
EngineAPIResolver. In the current API:
- set
nameon the field; - set
onSubmiton the EngineForm to a named page handler; - receive the collected object in that handler;
- pass it to EngineAPIResolver if the form is network-backed.
This keeps form collection and network orchestration separate and explicit.