From 6297e3b3e090d8f4057d66da69e3cc5ce0d72ea0 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 18 Aug 2026 20:17:22 +0000 Subject: [PATCH] docs(blocks): teach a validation shape the input node actually declares (#5229) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The "Add Validation" section of content/docs/blocks/forms.mdx taught a `validation` object on a `"type": "input"` node, carrying a flat string `pattern` and a sibling `message` key. `InputSchema` declares no `validation` key at all, and `BaseSchema` is `.passthrough()`, so the whole object rode through unvalidated: `objectui validate` accepted it (it accepts `"validation": {"pattern": 12345, "message": false}` just as happily), `InputRenderer` never reads `schema.validation`, and form.tsx's #5099 diagnostic walks a form node's `fields[]` rather than standalone input nodes. A reader copying the example got zero validation and zero diagnostics from every tool we ship. Replaced with the keys the node actually declares and the renderer actually reads: `required` and `pattern` (a string), forwarded to the native HTML input attributes at input.tsx:56. Added the `form` component's `fields[].validation` route for rule objects with custom messages, in the `{ value, message }` shape FieldConstraintsSchema pins, and stated why `pattern` alone cannot come from JSON there — react-hook-form runs it only when `value instanceof RegExp` — pointing at the field-metadata route and the TypeScript form instead. Swept the whole file: this was the only occurrence of the dialect. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01RV6yuVCxymHYE16PL9vQkE --- content/docs/blocks/forms.mdx | 47 ++++++++++++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 4 deletions(-) diff --git a/content/docs/blocks/forms.mdx b/content/docs/blocks/forms.mdx index c299981c10..da9be706f2 100644 --- a/content/docs/blocks/forms.mdx +++ b/content/docs/blocks/forms.mdx @@ -39,19 +39,58 @@ Customize form blocks for your application: ### Add Validation +The blocks on this page are built from plain `input` nodes, and an `input` +declares its own validation keys — `required`, `pattern`, `maxLength`, `min`, +`max` and `step` — which the renderer forwards to the native HTML input +attributes: + ```json { "type": "input", "name": "email", "inputType": "email", "required": true, - "validation": { - "pattern": "^[a-z0-9._%+-]+@[a-z0-9.-]+\\.[a-z]{2,}$", - "message": "Please enter a valid email address" - } + "pattern": "^[a-z0-9._%+-]+@[a-z0-9.-]+\\.[a-z]{2,}$" +} +``` + +`inputType: "email"` already gets the browser's own email check; `pattern` +tightens it. The browser enforces these constraints when the input is submitted +inside a `
`. + +An `input` node has **no `validation` key**. Rule objects with custom messages +belong to the [form component](/docs/components/form/form), whose `fields[]` +entries carry them. Every rule there is a `{ value, message }` object, and +`validation.required` supplies the message only — whether the field is required +is decided by `required` on the field itself: + +```json +{ + "type": "form", + "fields": [ + { + "name": "message", + "type": "textarea", + "label": "How can we help?", + "required": true, + "validation": { + "required": "Please tell us how we can help", + "minLength": { "value": 20, "message": "Please use at least 20 characters" }, + "maxLength": { "value": 2000, "message": "Please keep it under 2000 characters" } + } + } + ] } ``` +`pattern` is the one rule that route cannot take from JSON: react-hook-form runs +it only when the rule's `value` is a compiled `RegExp`, and no JSON document can +hold one. Declare the pattern on the object field's metadata instead (`pattern`, +a string, which `@object-ui/fields` compiles before the rule reaches the form), +or in a TypeScript-authored schema pass the real thing — +`pattern: { value: /.../, message: '...' }`. The full rule table is in the +[Form Plugin](/docs/plugins/plugin-form) reference. + ### Add Submit Action ```json