Who this is for. The developer building, styling or submitting a form who needs the facts about one element type. After this page you can say, for any element, what the editor configures, what markup the platform prints, what is stored, and what the server checks.

Every element the form builder offers, one entry each. How to choose between the types is on Fields, groups and static elements; the rules behind the Validates rows are on Validation rules and error handling.

Shared by every input, and not repeated below:

  • Settings: label, name, placeholder, help, default value, required, regex and custom CSS classes, as described on the elements page.
  • Markup: a wrapper <div class="base-element-block input-element-block"> plus any custom classes. Inside it, the label, the field (with class="element-input <editor>", id="element-<form id>-<name>" and data-id set to the element's id), and after a failed submit <div class="input-element-validation-errors">. The help text becomes the field's title.
  • Template path: none. Every element's markup is produced by the platform's PHP, not a template, so there is no file to override. To change one type's markup, print your own markup for elements of that editor in the form layout, and getHtml() for the rest (Rendering and styling).
  • Stored as: always a list. A single answer is a list of one, trimmed, and an empty answer is an empty list.

Text

Input field

EditorinputText
ConfiguresMinimum and maximum length
Renders<label> and <input type="text"> with minlength, maxlength, pattern (the regex) and required
Stored asThe text, trimmed
ValidatesRequired; regex; length
AccessibilityLabelled. Nothing marks it invalid after an error; see accessible errors

Textarea

EditorinputTextarea
ConfiguresMinimum and maximum length
Renders<label> and <textarea> with maxlength and required. No minlength: the minimum is checked by the server only
Stored asThe text, trimmed; line breaks kept
ValidatesRequired; regex; length
AccessibilityLabelled. State a minimum length in the label, since the browser does not enforce it

Email

EditorinputEmail
ConfiguresUnique: refuse an address already used in another completed submission of this form
Renders<label> and <input type="email"> with pattern and required
Stored asThe text, trimmed
ValidatesRequired; regex; unique against completed submissions when set. Not the format: that is the browser's type="email" only
AccessibilityLabelled. The browser's own format message is in the visitor's language and is announced

Phone

EditorinputTel
ConfiguresNothing beyond the shared settings
Renders<label> and <input type="tel"> with pattern and required. Mobile keyboards show digits
Stored asThe text, trimmed, in whatever format was typed
ValidatesRequired; regex. Nothing checks that it is a phone number unless a regex does
AccessibilityLabelled. Give the expected format in the label, not only in a placeholder

Hidden input

EditorinputHidden
ConfiguresThe default value, which is the value sent
Renders<input type="hidden"> alone, with no wrapper or label
Stored asThe text, trimmed
ValidatesRequired; regex. The visitor can change the value; see hidden inputs
AccessibilityNot announced

Numbers

Numeric

EditorinputNumber
ConfiguresMinimum, maximum, step
Renders<label> and <input type="number"> with min, max, step and required
Stored asA number. Spaces are removed and a comma becomes a decimal point, so 1 000 is 1000 and 1,5 is 1.5; 1.234,5 is refused
ValidatesIs a number; minimum; maximum; step, counted from the minimum. Use whole-number steps: a decimal step such as 0.1 can see a valid answer as not divisible
AccessibilityLabelled

Slider

EditorinputSlider
ConfiguresMinimum, maximum, step
Renders<label> and <input type="range" class="form-range"> with min and max. A step set on the element is not printed on the input, so the browser moves in steps of 1 while the server checks the configured step: add the step attribute with a line of script, or use Numeric. No required, and no display of the chosen number
Stored asA number
ValidatesAs Numeric
AccessibilityKeyboard-operable, but the visitor cannot see the value chosen. Show it with a few lines of script writing the value into an <output>, or use Numeric. A slider always has a value, so "required" means nothing for it

Range

EditorinputRange
ConfiguresMinimum, maximum, step, applied to both numbers
RendersOne <label> and two <input type="number" name="<name>[]">, from and to
Stored asTwo numbers, sorted lower first, whichever order they were typed in. Through the API the pair can also be sent as 10:20; send exactly two values
ValidatesAs Numeric, on both
AccessibilityBoth inputs get the same id, so the label points at the first and the second has no label. Add an aria-label to each ("From", "To") with a line of script, or use two Numeric fields when that matters

Choices

Select

EditorinputSelect
ConfiguresOptions (each a value and a title); Allow multi select; minimum and maximum number of choices
Renders<label> and <select>. A single select starts with an empty option whose text is the placeholder, or the title of an option with an empty value. A title written Group::Option puts the option in an <optgroup label="Group">. Multi select adds multiple and names the field <name>[]
Stored asThe chosen value, or for multi select the list of values without duplicates
ValidatesRequired. Not that the value is one of the options, and not the minimum or maximum number of choices
AccessibilityLabelled. Multi-selects are awkward on every platform; prefer a checkbox list for up to about ten options

Radio

EditorinputRadio
ConfiguresOptions
Renders<div class="radio-list list-group"> holding the label as a <div class="element-label">, then one <label class="list-group-item"> around each <input type="radio">, with ids ending -radio-0, -radio-1…. An option with an empty value is rendered disabled. No required attribute
Stored asThe chosen value
ValidatesRequired, on the server only. Not that the value is one of the options
AccessibilityEach option is labelled, but the question is not tied to the group: a screen reader announces "Yes, radio button" without the question. Put a radio question in its own element group, so its legend carries the question, or add role="radiogroup" and aria-labelledby with script

Checkbox

EditorinputCheckbox
ConfiguresOptions; minimum and maximum number ticked
RendersOne option: a single <input type="checkbox"> with its label as a real <label>, and required when required. Two or more: <div class="checkbox-list list-group"> with the label as a <div> and one labelled box per option, named <name>[], with ids ending -checkbox-0…, and no required
Stored asOne option: its value when ticked, nothing when not. Several: the list of ticked values
ValidatesRequired (for a list: at least one ticked). Not the minimum or maximum number ticked
AccessibilityA single box is fully labelled, which suits consent. A list has the same problem as Radio; give it a group

Dates, files and the rest

Date/Time

EditorinputDatetime
ConfiguresMode (date, time, or date and time); earliest and latest
Renders<label> and <input type="date">, type="time" or type="datetime-local", with min, max and required. No placeholder
Stored asThe browser's text: 2026-10-05, 14:30 or 2026-10-05T14:30. No time zone is recorded
ValidatesRequired; earliest and latest
AccessibilityThe browser's own date control, which is accessible in current browsers

File

EditorinputFile
ConfiguresAllow multiple file uploads
Renders<label> and <input type="file"> with required, and multiple with the name <name>[] when allowed. No accept. The form layout must add enctype="multipart/form-data" when hasFileInput() is true
Stored asEach file is saved to the Files manager under user-files/form-submissions/<form name>/<submission token>/, and the answer is a list of {type, id, name, link}, where type is image or file and link is the file's address, starting /files/
ValidatesRequired, which only a file sent as a multipart/form-data file part meets: a file sent as a data URL in JSON does not count (Submitting a form through the API). No type or size limit beyond the server's upload limit. Who can open the file afterwards: see File uploads
AccessibilityLabelled. A failed submit cannot refill it, so say "choose the file again" in the error summary

Captcha

EditorinputCaptcha
ConfiguresMode: "I am not a robot" checkbox, or an invisible badge. On the form: Require completed captcha
Renders<div class="g-recaptcha"> with the site key, a small inline script and Google's recaptcha/api.js, both carrying the page nonce. The checkbox mode also renders a label and a helper checkbox that the widget ticks when solved. The invisible mode takes over the enclosing form's submit
Stored asNothing: the token is checked with Google and dropped
ValidatesAlways required, and verified. Without Require completed captcha, a submission without a solved captcha is still saved, as incomplete; with it, nothing is saved (422 from the API). Tick it on every public form (Captcha)
AccessibilityGoogle's widget, with Google's own audio challenge

Submit button

EditorinputSubmitButton
ConfiguresThe label is the button text
Renders<button type="submit" name="<name>">, with no wrapper and no class
Stored asNothing, but it counts as an input when the platform decides whether a submission is complete
ValidatesNothing
AccessibilityA real button. Use it instead of the layout's button, not as well as it

Groups, static elements and payment

Element group

Editorgroup
ConfiguresGroup title; the elements inside it
Renders<fieldset class="element-block element-group-block"> with the title as <legend class="element-label element-text">, then each child's own markup
Stored asNothing; its children are stored as themselves
AccessibilityThe legend is announced with each field: the right container for radio questions, checkbox lists and addresses

Richtext

EditorstaticRichtext
ConfiguresThe content, in the rich-text editor
Renders<div class="element-block static-element-block"><div class="element-text">, then the content as stored
Stored asNothing
AccessibilityOrdinary content. Use real headings and links inside it

HTML snippet

EditorstaticCode
ConfiguresRaw HTML and script
RendersThe content exactly as entered, with no wrapper. Every <script> is given the page's nonce, so it runs. See the note on static elements
Stored asNothing
AccessibilityWhatever the HTML provides

Payment

Typepayment
ConfiguresCurrency, preset amounts, custom amount, capture mode, payment methods, tax category
Renders and storesCovered on Taking payments. It needs the platform's /assets/forms/js-payment-element.js (js-payment-element.js reference) and is processed only once every other answer on the form is valid