Form ID

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.

Form definition
{
  "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

KeyRequiredRules
versionYesAlways 1
titleYes1 to 200 characters
descriptionNoUp to 2,000 characters
fieldsYes1 to 100 fields with unique ids, at most 2,000 options in total
settings.submit_labelNo1 to 100 characters, used by renderers such as the shadcn/ui component
settings.success_messageNo1 to 1,000 characters
settings.redirect_urlNoAn http: or https: URL up to 2,048 characters
$schemaNoAny 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

KeyRequiredRules
idYesLowercase snake_case, starts with a letter, at most 64 characters, for example team_size
typeYesOne of the 12 types below
labelYes1 to 200 characters. Used in error pages and notification emails
requiredNotrue makes an empty value an error
placeholderNoUp to 200 characters
help_textNoUp 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

TypeStored asAccepts
textstringAny single-line text
textareastringMulti-line text
emailstring, domain lowercasedOne email address
numbernumberNumbers, or numeric strings from HTML forms
selectstringOne listed option value
radiostringOne listed option value
multi_selectstring[]Listed option values, duplicates removed
checkboxbooleanon, true, 1, yes, or nothing
datestring, YYYY-MM-DDA real calendar date
urlstring, normalizedA web address, https:// added when missing
phonestringDigits, spaces, + ( ) . -
ratingintegerA whole number from 1 to max

text

validationValuesDefault
min_length0 to 10,000None
max_length1 to 10,000, or at most 256 with a pattern1,000, or 256 with a pattern
patternA regular expression up to 200 characters, matched against the whole valueNone
pattern_message1 to 200 charactersInvalid 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

KeyValuesDefault
validation.min_length0 to 16,000None
validation.max_length1 to 16,00010,000
rows1 to 50, a display hint for renderersNone

email

validationValuesDefault
allowed_domains1 to 100 domains such as example.com, matched exactlyAny domain

Addresses longer than 254 characters are refused. The domain part is stored lowercased; the part before @ is kept as sent.

number

validationValuesDefault
minAny numberNone
maxAny number, at least minNone
integertrue to refuse decimalsfalse

select, radio and multi_select

KeyValuesDefault
options1 to 500 { "value", "label" } objects with unique values, each 1 to 200 charactersRequired
validation.min_itemsmulti_select only, 0 to 5000, or 1 when required
validation.max_itemsmulti_select only, 1 to 500The 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

validationValuesDefault
minA YYYY-MM-DD dateNone
maxA YYYY-MM-DD date, on or after minNone

url

validationValuesDefault
https_onlytrue to refuse http:false
max_length1 to 4,0962,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

validationValuesDefault
e164true to require international format, stored without separatorsfalse

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

validationValuesDefault
max2 to 105

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:

Posted, urlencoded
name=++Ada+Lovelace++&email=Ada@Example.COM&guests=3&newsletter=on&site=example.com&phone=%2B1%20415%20555%200123
Stored, with phone set to e164
{
  "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.5 or 1e3.

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.

422 Unprocessable Content
{
  "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

ProblemMessage
Missing required valueThis field is required
Required checkbox uncheckedThis box must be checked
Too short or too longMust be at least 10 characters, Must be at most 120 characters
Pattern mismatchYour pattern_message, or Invalid format
EmailEnter a valid email address, Email must be at one of: example.com
NumberEnter a number, Enter a whole number, Must be at least 1
OptionsChoose one of the listed options, Choose at least 2 options, Choose at most 3 options
DateEnter a valid date (YYYY-MM-DD), Must be on or after 2026-01-01
URLEnter a valid URL, Enter a valid https:// URL
PhoneEnter a valid phone number, Use international format, e.g. +14155550123
RatingChoose 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.