Fields
This guide covers how to describe a form's fields with the items array, connect each field to your data, pass options through to the underlying controls, edit several data keys from one control, and render a single field read-only.
items is an array of field configurations and values is the plain object those fields read and write. Each item points at a control through comp and at a piece of data through key. The editor never edits values directly - it keeps an internal draft copy, applies edits and validation there, and writes changed fields back to values only on save. That means the shape of values stays exactly the data you'd store anyway; the item config is the only place the form's structure lives.
Common item shape
An item is a plain object. The three properties you'll set on almost every field are comp (which control to render), key (which data entry it edits), and label (the text shown beside it). The built-in comps text, textarea, and checkbox work with no setup:
import { Editor } from "@svar-ui/react-editor";
const items = [
{ comp: "text", key: "name", label: "Name" },
{ comp: "textarea", key: "descr", label: "Description" },
{ comp: "checkbox", key: "admin", label: "Is Admin" }
];
const values = {
name: "John Doe",
descr: "Team lead on the platform group",
admin: true
};
function App() {
return <Editor items={items} values={values} />;
}
If you omit comp, the item falls back to text. For any other control - a date picker, a rich select, a code editor - register it under a name first and then reference that name as comp; see Input controls.
Value mapping
A plain key reads and writes values[key]. When your data is nested, use a dot path - the editor resolves it through generated getter and setter functions, as long as the intermediate objects already exist:
import { Editor } from "@svar-ui/react-editor";
const items = [
{ comp: "text", key: "person.name", label: "Name" }
];
const values = {
person: { name: "Alex" }
};
function App() {
return <Editor items={items} values={values} />;
}
When neither a flat key nor a dot path fits your data shape, supply your own getter and setter. The getter reads the field's value out of the record; the setter writes it back:
const items = [
{
comp: "text",
key: "title",
label: "Title",
getter: record => record.meta.title,
setter: (record, value) => {
record.meta.title = value;
}
}
];
Item specific configuration
Any extra properties on an item that aren't part of the config it interprets are forwarded straight to the rendered control, so most of a widget's own props can be set inline on the item.
config is shallow-merged onto the item before it renders, which is a convenient place to group control-specific props. If the same key appears both at the top level and inside config, the config value wins:
const items = [
{ comp: "textarea", key: "descr", label: "Description", config: {
placeholder: "Add description"
}}
];
options is passed through to controls that need a choice list - a rich select, a radio group - and the read-only renderer reuses it to turn a stored value back into its label. When a static label isn't enough, labelTemplate(value) computes the displayed label from the current value.
Multi-field items
Sometimes one control edits several data keys at once - a date range that owns a start, an end, and an all-day flag. Use keys instead of key: the control receives a composite object keyed by those entries and emits the whole next composite back. The editor still tracks each underlying field separately, so onSave reports the real field keys that changed, not the item id:
import { useState } from "react";
import { Editor, registerEditorItem } from "@svar-ui/react-editor";
import EventDates from "./EventDates.jsx";
registerEditorItem("event-dates", EventDates);
const items = [
{ comp: "text", key: "name", label: "Name" },
{
comp: "event-dates",
key: "dates",
keys: ["start", "end", "isFullDay"],
label: "Event dates",
validation: v => !v.start || !v.end || v.end >= v.start,
validationMessage: "End date must be after the start date"
}
];
function App() {
const [values] = useState({
name: "Project kickoff",
start: new Date(2026, 5, 10, 9),
end: new Date(2026, 5, 10, 11),
isFullDay: false
});
return <Editor items={items} values={values} topBar={false} autoSave={true} />;
}
Validation on a multi-field item runs against the whole composite, so validation(v) and required see every member at once - required here means each of the listed keys must have a truthy value.
Read-only items
Use the built-in "readonly" comp to make a single field display-only while the rest of the form stays editable:
const items = [
{ comp: "readonly", key: "name", label: "Name" }
];
The field is rendered as text instead of an input: booleans print as Yes/No, options resolve to their matching label, dates are formatted, and an empty value renders nothing. The item still takes part in value mapping, so key, getter, and options work exactly as they do for editable fields - only the control changes.
To switch the whole form to a view-only presentation, use the readonly prop instead of marking every item; see Display modes.