← UniformCONTENT HISTORY

Update to Uniform

Snapshot Sep 30, 2026 · 23:15 UTC · version 1.0.0

Collection source: not recorded for this historical snapshot.

WHAT CHANGED · RULE-BASED ANALYSIS

First saved snapshot

No earlier snapshot is available to establish a change.

Compare saved observations

Download comparison JSON
Full technical diff · 0 changed fields
Full snapshot data
{
  "description": "Use when adding a form (like contact, signup, newsletter, lead-capture or survey) to a Uniform project, when creating form field component definitions or building a generic form submission endpoint. Do not use when embedding an iframe for an external form provider.",
  "included_files": [
    {
      "relative_path": "agents/openai.yaml",
      "size_in_bytes": 163
    },
    {
      "relative_path": "references/modeling.md",
      "size_in_bytes": 7875
    },
    {
      "relative_path": "references/submission.md",
      "size_in_bytes": 2604
    }
  ],
  "name": "uniform-forms",
  "skill_md_contents": "---\nname: uniform-forms\ndescription: >-\n  Use when adding a form (like contact, signup, newsletter, lead-capture or survey) to a\n  Uniform project, when creating form field component definitions or building a generic form submission endpoint.\n  Do not use when embedding an iframe for an external form provider.\nlicense: MIT\n---\n\n# Uniform forms\n\nA form in Uniform is not a special entity — it is a **composition of components**. A `Form` container component renders the `<form>` element and owns the resulting submit action; each input is its own component placed in the container's slot. Authors assemble forms in Uniform's visual editor; developers own the markup, state, and submission.\n\n## Architecture\n\n```\nform                       container: renders <form>, owns state, submits\n├── slot: formFields       formTextField, formTextAreaField, formSelectField,\n│                          formCheckboxField, formRadioField (+ $personalization, $test)\n└── slot: formButtons      formButton (min 1) (+ $personalization, $test)\n\nformSelectField / formRadioField\n└── slot: options          formSelectOption, formRadioOption (+ $personalization, $test)\n```\n\nField components **self-register** with that context on mount and read/write their own value through it. The container never inspects its slot contents.\n\n## Author-set Field name and identifier\n\n**Every field must have a stable, author-set identifier.** The `name` parameter is required on every field component. Slugify it to get the identifier used for the HTML `name`/`id`, and the payload key. **Never fall back to a generated identifier, warn in the Uniform's visual editor when a field is missing an identifier**.\n\n## Form Submit or Fields should self-register\n\n**Do not introspect slots.** Do not walk `component.slots.formFields` to build fields. That code can easily miss fields nested inside `$personalization` or `$test` wrappers, and duplicates the slot's structure in two places. Use the form submit event to gather the data or self-register each field based on the component's nested context.\n\n## Options are a slot, not a `$block` parameter\n\nDropdown and radio options are components in an `options` slot. This is good practice for these components as it allows them to be personalized, be A/B tested, or support visibility conditions. Do not use blocks or a `$block` parameter as **it cannot be created or edited via MCP or AI**, so a block-based model cannot be built or maintained by an agent.\n\n## Restrict every slot explicitly\n\n**Never set `allowAllComponents: true`.** List the field components, and add `$personalization` and `$test` to `formFields` so individual fields can be optimized.\n\n## Always validate on the server\n\nClient-side validation, `required`, `minlength`, `maxlength`, `pattern` and other built-in form input parameters drive the HTML validation UX only. Re-check every required field in the API route.\n\n## Keep track of the form submit state\n\nTrack `idle | submitting | success | error`. Disable the submit button while submitting and render the result in the page with `aria-live`. Never use `alert()` or `confirm()`.\n\n## Build order\n\n1. **Model the components** in Uniform — `form` first, then fields, then `formButton`, then `formSelectOption`. See [modeling.md](references/modeling.md).\n2. **Build a single API route** to receive submissions according to the payload contract. See [submission.md](references/submission.md).\n3. **Build the form submission logic** to send submissions according to the payload contract.\n5. **Build all components** in the current tech stack and ensure the `<form>` submit event triggers the form submission logic.\n6. **Assemble a form in Uniform's visual editor** and submit it to confirm the payload keys match the authored field names.\n\n## Payload contract\n\nThe container POSTs this to `/api/forms/submit` which expects the payload contract defined in [submission.md](references/submission.md).\nThe generic nature of the payload means that it is important to have some mitigation for potential spam or malicious requests.\n\n## References\n\n- [Modeling](references/modeling.md) — component definitions for the form with parameter tables and slot restrictions\n- [Submission](references/submission.md) — the API route, payload contract and server-side validation\n"
}

SHA-256 of public snapshot: a8b8bd690ef33e072362e1ef6840c62a338b5802c83e0b9028117d0f6785c4cf