Fields and validation
Define fields once and Ikiform validates every submission on the server, with clear messages and typed values.
Fields are optional. A form without fields accepts any data your form sends. Once you publish fields, Ikiform validates every submission against them on the server, rejects bad data with clear messages, and stores clean, typed values.
Defining fields
Open a form in the dashboard and go to Fields. Add fields in the visual editor or edit the JSON definition directly. Each field's id is the input name your form must send.
{
"version": 1,
"title": "Contact",
"fields": [
{ "id": "name", "type": "text", "label": "Name", "required": true, "validation": { "max_length": 120 } },
{ "id": "email", "type": "email", "label": "Email", "required": true },
{
"id": "topic",
"type": "select",
"label": "Topic",
"options": [
{ "value": "sales", "label": "Sales" },
{ "value": "support", "label": "Support" }
]
},
{ "id": "message", "type": "textarea", "label": "Message", "validation": { "min_length": 10 } }
],
"settings": { "submit_label": "Send", "success_message": "Thanks, we'll reply within a day." }
}The definition
| Key | Required | Rules |
|---|---|---|
version | Yes | Always 1 |
title | Yes | 1 to 200 characters |
description | No | Up to 2,000 characters |
fields | Yes | 1 to 100 fields with unique ids, at most 2,000 options in total |
settings.submit_label | No | 1 to 100 characters, used by renderers such as the shadcn/ui component |
settings.success_message | No | 1 to 1,000 characters |
settings.redirect_url | No | An http: or https: URL up to 2,048 characters |
$schema | No | Any string up to 200 characters, ignored |
Unknown keys are refused, at the top level and on every field, so a typo like requried shows up as an error when you save.
Keys on every field
| Key | Required | Rules |
|---|---|---|
id | Yes | Lowercase snake_case, starts with a letter, at most 64 characters, for example team_size |
type | Yes | One of the 12 types below |
label | Yes | 1 to 200 characters. Used in error pages and notification emails |
required | No | true makes an empty value an error |
placeholder | No | Up to 200 characters |
help_text | No | Up to 1,000 characters |
Playground
201 Created: the server would store this
{
"ok": true,
"id": "sub_01k7v2c9t3e8m5q4x6z0a1b2c3"
}Runs Ikiform's own validator in your browser. Fields that start with an underscore are reserved and dropped before validation, as on the server.
Field types
| Type | Stored as | Accepts |
|---|---|---|
text | string | Any single-line text |
textarea | string | Multi-line text |
email | string, domain lowercased | One email address |
number | number | Numbers, or numeric strings from HTML forms |
select | string | One listed option value |
radio | string | One listed option value |
multi_select | string[] | Listed option values, duplicates removed |
checkbox | boolean | on, true, 1, yes, or nothing |
date | string, YYYY-MM-DD | A real calendar date |
url | string, normalized | A web address, https:// added when missing |
phone | string | Digits, spaces, + ( ) . - |
rating | integer | A whole number from 1 to max |
text
| validation | Values | Default |
|---|---|---|
min_length | 0 to 10,000 | None |
max_length | 1 to 10,000, or at most 256 with a pattern | 1,000, or 256 with a pattern |
pattern | A regular expression up to 200 characters, matched against the whole value | None |
pattern_message | 1 to 200 characters | Invalid format |
Patterns run with the u flag and must match the whole value. When you save, Ikiform refuses patterns that could backtrack catastrophically: backreferences, repeated groups that contain repeats or alternatives ((a+)+, (a|b)*), and too many nested repeats.
textarea
| Key | Values | Default |
|---|---|---|
validation.min_length | 0 to 16,000 | None |
validation.max_length | 1 to 16,000 | 10,000 |
rows | 1 to 50, a display hint for renderers | None |
| validation | Values | Default |
|---|---|---|
allowed_domains | 1 to 100 domains such as example.com, matched exactly | Any domain |
Addresses longer than 254 characters are refused. The domain part is stored lowercased; the part before @ is kept as sent.
number
| validation | Values | Default |
|---|---|---|
min | Any number | None |
max | Any number, at least min | None |
integer | true to refuse decimals | false |
select, radio and multi_select
| Key | Values | Default |
|---|---|---|
options | 1 to 500 { "value", "label" } objects with unique values, each 1 to 200 characters | Required |
validation.min_items | multi_select only, 0 to 500 | 0, or 1 when required |
validation.max_items | multi_select only, 1 to 500 | The number of options |
Only listed values are accepted. select and radio take one value; send multi_select as repeated names, name[] or a JSON array.
checkbox
No extra keys. A missing checkbox is false. required: true means it must be checked, which suits consent boxes. Values other than on, true, 1, yes, off, false, 0, no or empty are refused.
date
| validation | Values | Default |
|---|---|---|
min | A YYYY-MM-DD date | None |
max | A YYYY-MM-DD date, on or after min | None |
url
| validation | Values | Default |
|---|---|---|
https_only | true to refuse http: | false |
max_length | 1 to 4,096 | 2,048 |
Only http: and https: URLs with a dotted hostname and no username or password are accepted. The stored value is the normalized URL.
phone
| validation | Values | Default |
|---|---|---|
e164 | true to require international format, stored without separators | false |
Without e164, a phone number needs 6 to 15 digits and is stored as sent. With it, +1 (415) 555-0123 is stored as +14155550123.
rating
| validation | Values | Default |
|---|---|---|
max | 2 to 10 | 5 |
Coercion
HTML forms send everything as text. Ikiform turns it into the type each field declares before storing. With name as text, email, guests as a number, newsletter as a checkbox, site as a URL and phone as a phone field:
name=++Ada+Lovelace++&email=Ada@Example.COM&guests=3&newsletter=on&site=example.com&phone=%2B1%20415%20555%200123{
"name": "Ada Lovelace",
"email": "Ada@example.com",
"guests": 3,
"newsletter": true,
"site": "https://example.com/",
"phone": "+14155550123"
}- Values are trimmed. An empty string counts as missing.
- A field that expects one value refuses an array with more than one item.
- Numbers accept plain decimal and exponent notation up to 64 characters, such as
3,-2.5or1e3.
Validation errors
A submission that fails validation is rejected with 422 validation_failed and nothing is stored. error.fields maps each field id to its messages. Browser posts see the same messages on a hosted error page, labelled with your field labels.
{
"ok": false,
"error": {
"code": "validation_failed",
"message": "Some fields are invalid.",
"fields": {
"email": ["Enter a valid email address"],
"website": ["Unknown field \"website\""]
}
},
"request_id": "req_01k7v2c9t3e8m5q4x6z0a1b2c3"
}Unknown fields
With fields defined, any field that is not in the definition is rejected as Unknown field "name". Reserved fields that start with _, the honeypot and cf-turnstile-response don't count. Without a definition, any field names are accepted.
Messages
| Problem | Message |
|---|---|
| Missing required value | This field is required |
| Required checkbox unchecked | This box must be checked |
| Too short or too long | Must be at least 10 characters, Must be at most 120 characters |
| Pattern mismatch | Your pattern_message, or Invalid format |
Enter a valid email address, Email must be at one of: example.com | |
| Number | Enter a number, Enter a whole number, Must be at least 1 |
| Options | Choose one of the listed options, Choose at least 2 options, Choose at most 3 options |
| Date | Enter a valid date (YYYY-MM-DD), Must be on or after 2026-01-01 |
| URL | Enter a valid URL, Enter a valid https:// URL |
| Phone | Enter a valid phone number, Use international format, e.g. +14155550123 |
| Rating | Choose a rating, Rating must be at most 5 |
Validating in the browser
The SDK's validate mirrors the server rules and messages for all 12 field types, so you can show errors before posting. The server stays the source of truth. See validate.