Value Coercion
📖 Table of Contents
SmarkForm normalizes imported values according to component type and shape. This can help with data-model changes, such as evolving a scalar field into a list. The rules below describe the supported conversions and their limits.
Scalar-to-Array List Coercion
When a list field receives a non-array value — a string, number, object, or null — it wraps that value in a single-item array. undefined is special: it resets the list to its current default instead.
This is particularly useful for model migrations: if a field that used to hold a single email string is upgraded to accept a list of emails, old saved data continues to work without any transformation step.
Exporting Empty Items
By default, empty items are not exported (export_empties: false). This keeps saved data clean by omitting blank rows.
Set "export_empties": true on the list to preserve empty slots — useful in draft-save workflows where you want to retain the user’s position in the list.
<div id="myForm">
<button data-smark='{"action":"removeItem","context":"email","preserve_non_empty":true}' title="Remove email">➖</button>
<button data-smark='{"action":"addItem","context":"email"}' title="Add email">➕</button>
<strong data-smark="label">Emails:</strong>
<ul data-smark='{"type":"list","name":"email","of":"input","min_items":0}'>
<li data-smark-role="empty_list">(No emails on record)</li>
<li><input type="email" data-smark placeholder="name@example.com"></li>
</ul>
</div>
#myForm ul {
list-style: none;
padding-left: 0;
}
const myForm = new SmarkForm(document.getElementById("myForm"), {
"value": {
"email": "alice@example.com"
}
});
👉 Scalar-to-array coercion: If you import a plain string instead of an array, SmarkForm automatically places it in a single-item list.
- Click ⬇️ Export, change
["alice@example.com"]to just"alice@example.com"in the JSON playground editor below, then click ⬆️ Import — the single email is placed in the list automatically. - This mirrors the upgrade from a single-value field (e.g.
"email") to a list field (e.g."emails": [...]).
👉 Empty items are not exported by default (controlled by export_empties).
- Click ➕ to add a blank item, then ⬇️ Export — the blank row will be absent from the output, keeping saved data clean.
- Set
"export_empties": trueon the list to keep blank slots in the data (useful in draft-save workflows where you want to preserve the user’s position in the list).
Number, Date, Time, and JSON Coercion
Fields with a specific HTML type automatically coerce values on both import and export:
<input type="number">exports a JavaScript number (not a string), and accepts string representations on import (e.g."28"→28).<input type="date">exports an ISO 8601 string (YYYY-MM-DD), and accepts compact strings (YYYYMMDD) andDateobjects on import.<input type="time">exportsHH:MM:SSand acceptsHH:MMon import.- Time fields also accept
Dateobjects and epoch-millisecond numbers on import. - Value types with no natural empty state —
number,date,time,datetime-local,color,radio,file… — exportnullwhen empty, to explicitly signal “unknown or indifferent” rather than""or0. - Plain text fields (
<input type="text">,<textarea>) are the exception: they export an empty string (""), because a native text input does not distinguish “empty” from “no value”. A text field withformat:"json"does exportnullwhen empty (see below).
JSON format
Adding {"format":"json"} (or the legacy alias encoding:"json") to an <input> or <textarea> enables JSON parsing and serialization: the field stores JSON text and exports a parsed JavaScript value.
Current limitation: the JSON field’s export uses falsey parsed values as its empty state. Therefore
0,false,"", andnullexport asnull; do not use this option when those values must round-trip distinctly.
For import/export lifecycle, defaults, and target copying, see Importing and Exporting Data.
<div id="myForm">
<p>
<label data-smark>Name:</label>
<input type="text" name="name" data-smark>
</p>
<p>
<label data-smark>Age:</label>
<input type="number" name="age" min="0" max="150" data-smark>
</p>
<p>
<label data-smark>Date of Birth:</label>
<input type="date" name="dob" data-smark>
</p>
<p>
<label data-smark>Metadata (JSON):</label>
<textarea name="metadata" data-smark='{"format":"json"}'></textarea>
</p>
</div>
const myForm = new SmarkForm(document.getElementById("myForm"), {
"value": {
"name": "Alice",
"age": "28",
"dob": "19960315",
"metadata": {
"subscribed": true,
"tier": "premium"
}
}
});
👉 Number coercion: The Age field is <input type="number">.
- SmarkForm always exports its value as a JavaScript number, not a string.
- It also accepts string representations on import — try clicking ⬇️ Export, changing
"age": 28to"age": "28"(quoted) in the JSON playground editor, and clicking ⬆️ Import: the exported result will be"age": 28(unquoted) again.
👉 Date normalization: The Date of Birth field is <input type="date">.
- SmarkForm always exports an ISO 8601 string (
YYYY-MM-DD). - It accepts compact strings (
YYYYMMDD) andDateobjects on import. Try clicking ⬇️ Export, changing"dob": "1996-03-15"to"dob": "19960315"in the JSON playground editor, and clicking ⬆️ Import — it will be normalised to"1996-03-15"on the next export.
👉 JSON format: The Metadata textarea has {"format":"json"}.
- On import, an object or array is serialised to JSON text (pretty-printed in textareas for readability).
- On export, the textarea content is parsed back into a JavaScript value — your saved data contains a real object, not a raw JSON string.
- Works with any valid JSON: objects, arrays, numbers, booleans, and
null.
See also: Data Import and Export, Form Types, List Types