Skip to content

Field kinds

Every field has a kind. The kind decides which options the field accepts, what value it holds at runtime, how that value is serialized for the model, and which control renders it. All kinds also accept the shared field options.

Kind Runtime value Renders as Kind options
text string single-line input placeholder, minLength, maxLength, pattern
long-text string multi-line text area placeholder, minLength, maxLength, rows
number number, draft string, or null numeric input or slider min, max, step, unit, placeholder
boolean boolean or null two-option radio group trueLabel, falseLabel
category string or null select options
single-choice string or null radio group options, layout
multi-choice string[] checkbox group options, layout
rating number or null row of score buttons max, min, step
date Date or null date input min, max, step
mapped-category string or null select options with mapping
onehot-category string or null select options with mappedTo
series array of row objects editable table columns, minPoints, maxPoints, aggregations

The screenshots on this page are the built-in controls with the eshkra theme. Each code block is the exact configuration that produced the screenshot beside it.

text and long-text hold a string; an empty field is "". minLength, maxLength, and pattern (a regular expression source, text only) apply to non-empty values, so combine them with required when the field must be filled. Use rows to set the visible height of a long-text area.

A Station name text field containing North station, marked valid.A Station name text field containing North station, marked valid.
{
id: "text",
kind: "text",
label: "Station name",
defaultValue: "North station",
required: true,
}
An Observation notes text area with three lines of text.An Observation notes text area with three lines of text.
{
id: "long-text",
kind: "long-text",
label: "Observation notes",
defaultValue: "Clear sky. Readings collected in the shade.",
rows: 3,
}

number holds a number, or null when empty. While the user types something that is not yet a number, such as - or 1e, the field keeps the text as a draft string, shows it as invalid, and blocks submission; it never coerces the draft to a number or to empty. min, max, and step are validated, with step counted from min (or from 0 without min). unit is displayed next to the value and never submitted.

A Humidity field showing 140 % with the error Maximum value is 100.A Humidity field showing 140 % with the error Maximum value is 100.
{
id: "invalid",
kind: "number",
label: "Humidity",
unit: "%",
defaultValue: 58,
min: 0,
max: 100,
required: true,
}

An optional number with both min and max and a numeric defaultValue renders as a slider; required numbers and numbers without both bounds render as a text input. Override the choice with ui: { input: "range" } or ui: { input: "text" }. The choice does not change while the user edits.

A Confidence threshold slider set to 75 %.A Confidence threshold slider set to 75 %.
{
id: "range",
kind: "number",
label: "Confidence threshold",
unit: "%",
defaultValue: 75,
min: 0,
max: 100,
step: 1,
}

Number fields and numeric series cells share one parsing rule:

  • Empty input becomes null.
  • A decimal may use a dot or a single comma, with an optional exponent such as 1e-8. Grouping separators, hexadecimal, and binary notation are not accepted.
  • Non-finite results, overflow, non-zero values that underflow to zero, and integer strings that would round to a different integer are invalid.
  • The editor keeps the text as typed, including trailing zeros and caret position; runtime values and payloads contain normalized numbers. Arrow keys step by step.

MLForm uses JavaScript numbers, not arbitrary-precision decimals. Invalid drafts survive draft snapshots so unfinished input is not lost.

boolean holds true, false, or null before the user chooses. false is a value: required asks for a choice, not for agreement. Rename the two options with trueLabel and falseLabel.

An Enable alerts switch with Enabled selected and Disabled unselected.An Enable alerts switch with Enabled selected and Disabled unselected.
{
id: "boolean",
kind: "boolean",
label: "Enable alerts",
defaultValue: true,
trueLabel: "Enabled",
falseLabel: "Disabled",
}

All three take options as strings or { label, value } objects; the value is what the model receives, the label is what people read. A value outside options is invalid.

  • category renders a select and holds one value or null.
  • single-choice renders the options as a radio group. Use it for a few options that people should see at once.
  • multi-choice renders checkboxes and holds an array of selected values, without duplicates. An empty array counts as empty for required.

layout: "horizontal" lays the choices of single-choice and multi-choice out in a row; the default is "vertical".

A Sensor location select with Outdoor selected.A Sensor location select with Outdoor selected.
{
id: "category",
kind: "category",
label: "Sensor location",
options: ["Indoor", "Outdoor", "Greenhouse"],
defaultValue: "Outdoor",
}
A Prediction window radio group with Next hour, Next day selected, and Next week.A Prediction window radio group with Next hour, Next day selected, and Next week.
{
id: "single-choice",
kind: "single-choice",
label: "Prediction window",
options: ["Next hour", "Next day", "Next week"],
defaultValue: "Next day",
}
A Signals to include checkbox group with Temperature and Humidity checked and Wind unchecked.A Signals to include checkbox group with Temperature and Humidity checked and Wind unchecked.
{
id: "multi-choice",
kind: "multi-choice",
label: "Signals to include",
options: ["Temperature", "Humidity", "Wind"],
defaultValue: ["Temperature", "Humidity"],
}

rating holds an integer score from min (default 1) to max (required), in increments of step (default 1). Scores render as a radio group of buttons; arrow keys, Home, and End move the selection.

An Observation quality rating with buttons 1 to 5 and 4 selected.An Observation quality rating with buttons 1 to 5 and 4 selected.
{
id: "rating",
kind: "rating",
label: "Observation quality",
max: 5,
defaultValue: 4,
}

date holds a Date, or null. It accepts ISO strings and Date objects as defaultValue and initialValues, and submits a full ISO timestamp such as "2026-06-15T00:00:00.000Z". min and max are date strings; step is a number of days counted from min, or from 1 January 1970 without min.

An Observation date field showing 15 June 2026.An Observation date field showing 15 June 2026.
{
id: "date",
kind: "date",
label: "Observation date",
defaultValue: "2026-06-15",
}

Required, constraint errors, read-only, disabled, and inline descriptions come from shared options and look the same across kinds.

Five fields: an empty required Station name with an inline description and the error This field is required; a valid Temperature; Humidity 140 with Maximum value is 100; a read-only Calibration offset with a muted background; and a disabled Sensor location select.Five fields: an empty required Station name with an inline description and the error This field is required; a valid Temperature; Humidity 140 with Maximum value is 100; a read-only Calibration offset with a muted background; and a disabled Sensor location select.
After form.validate(): required and constraint errors, a valid value, readOnly, and disabled.
  • Errors for non-empty values appear as soon as the value is set, including defaults and loaded values. Empty fields stay quiet until edited, blurred, or validated.
  • A read-only field shows its value and still validates; its text remains selectable.
  • A disabled or hidden field is inactive: it skips validation and, by default, is not submitted. See Conditions.

Three kinds turn one visible control into more than one model input. Each has its own page.

One visible field, several model valuesA one-hot category selected as rain sends weather_clear 0, weather_cloudy 0 and weather_rain 1. A mapped category selected as detailed writes 30 into the readings field, which submits through its own mappedTo. A series with rows 21, 22 and 23 sends mean 22, minimum 21 and maximum 23 through its aggregations.VISIBLE FIELDMODELVALUESonehot-categoryselected: "rain"one 0/1 column per optionweather_clear: 0weather_cloudy: 0weather_rain: 1mapped-categoryselected: "detailed"writes its mapping into fieldsreadings field = 30via the target field's mappedToreadings_per_hour: 30seriesrows: 21, 22, 23aggregations compute featuresmean: 22minimum: 21maximum: 23

Need a kind that is not here? Custom fields use the same registration, validation, and submission path as these built-ins.