Input Controls
This guide covers which controls an item can render out of the box, and how to bring in any other control for the rest - from SVAR Core, from the editor package itself, from a standalone widget package, or a fully custom component you write.
Registering a control
Every non-built-in control follows the same pattern: import the component and register it under a string with registerEditorItem, then reference that string from an item's comp. Registration is global and only needs to run once before the editor renders.
import { Editor, registerEditorItem } from "@svar-ui/react-editor";
import { DatePicker } from "@svar-ui/react-core";
registerEditorItem("datepicker", DatePicker);
const items = [
{ comp: "datepicker", key: "deadline", label: "Deadline" }
];
<Editor items={items} />
Built-in controls
These need no registration:
comp | Renders |
|---|---|
checkbox | Boolean toggle |
readonly | Static display-only value |
text | Single-line text input (also the default when comp is omitted) |
textarea | Multi-line text input |
One more built-in comp isn't an input at all: "section" renders a collapsible group header, see Layout.
checkbox
A checkbox binds a boolean value to a toggle:
import { Editor } from "@svar-ui/react-editor";
const items = [{ comp: "checkbox", key: "admin", label: "Is Admin" }];
const values = { admin: true };
<Editor items={items} values={values} />
readonly
A readonly item shows its value as text instead of an input, while the rest of the form stays editable. Booleans print as Yes/No, options resolve to their matching label, and dates are formatted:
import { Editor } from "@svar-ui/react-editor";
const items = [{ comp: "readonly", key: "name", label: "Name" }];
const values = { name: "John Doe" };
<Editor items={items} values={values} />
See Fields for the details, and Display modes for making the whole form view-only.
text
A text field binds a string value to a single-line input. It is also what an item renders when comp is omitted:
import { Editor } from "@svar-ui/react-editor";
const items = [{ comp: "text", key: "name", label: "Name" }];
const values = { name: "John Doe" };
<Editor items={items} values={values} />
textarea
A textarea binds a string value to a multi-line input. Extra props are forwarded to the control, so placeholder and the widget's own sizing props can be set right on the item:
import { Editor } from "@svar-ui/react-editor";
const items = [
{ comp: "textarea", key: "descr", label: "Description", placeholder: "Add description" }
];
const values = { descr: "Team lead on the platform group" };
<Editor items={items} values={values} />
Additional controls
Any control exported by @svar-ui/react-core, by the editor package itself, or by a standalone widget package, can be registered as described above. The controls below are the ones used most often - each links to its full prop reference.
Attachments
Bundled with the editor, Attachments renders a file list with upload/delete controls. Pass uploadURL - a function that receives the selected file and returns a promise resolving to the stored record - and an onAction callback to observe add/delete events. Its labels (Add file, Uploading..., Upload failed, Delete file) come from the editor locale.
import { Editor, registerEditorItem, Attachments } from "@svar-ui/react-editor";
registerEditorItem("files", Attachments);
registerEditorItem("files", Attachments, { readonly: true });
const uploadURL = file =>
fetch("/upload", { method: "POST", body: file }).then(r => r.json());
const items = [
{ comp: "files", key: "files", label: "Attachments", uploadURL, onAction: console.log }
];
<Editor items={items} />

CodeMirror
The editor package bundles CodeMirror, a syntax-highlighted code editor, directly - no extra package to install. It takes fill: true to stretch across the available height (see full-height single field), and language to set highlighting:
import { Editor, registerEditorItem, CodeMirror } from "@svar-ui/react-editor";
registerEditorItem("code-mirror", CodeMirror);
// register a handler for readonly mode too, otherwise it falls back to a plain text display
registerEditorItem("code-mirror", CodeMirror, { readonly: true });
const items = [
{ comp: "code-mirror", key: "content", label: "", fill: true, language: "javascript" }
];
<Editor items={items} />

ColorPicker
A swatch-and-picker control bound directly to a hex color string - no options needed. Same clear: true pattern as DatePicker to let users unset the value.
import { Editor, registerEditorItem } from "@svar-ui/react-editor";
import { ColorPicker } from "@svar-ui/react-core";
registerEditorItem("color", ColorPicker);
const items = [{ comp: "color", key: "color", label: "Color" }];
<Editor items={items} />
Full prop reference: ColorPicker
Combo
A single-select dropdown driven by a plain options array of { id, label } pairs. Because an item is just a plain object, you can replace its options at runtime - the pattern below rebuilds the city list whenever country changes, disabling city until a country is picked:
import { useState } from "react";
import { Editor, registerEditorItem } from "@svar-ui/react-editor";
import { Combo } from "@svar-ui/react-core";
registerEditorItem("combo", Combo);
const citiesByCountry = {
france: [{ id: "paris", label: "Paris" }, { id: "lyon", label: "Lyon" }]
};
function Demo() {
const [items, setItems] = useState([
{
comp: "combo",
key: "country",
label: "Country",
options: [{ id: "france", label: "France" }]
},
{ comp: "combo", key: "city", label: "City", disabled: true }
]);
const handleChange = ({ key, value }) => {
if (key === "country") {
const next = [...items];
next[1] = { ...next[1], disabled: false, options: citiesByCountry[value] };
setItems(next);
}
};
return <Editor items={items} onChange={handleChange} />;
}
Full prop reference: Combo
Comments
Comments comes from its own package, @svar-ui/react-comments, and manages an array of comment entries rather than a single value. users lists the people who can be shown as authors, and activeUser is the id of the person posting from this editor instance.
import { Editor, registerEditorItem } from "@svar-ui/react-editor";
import { Comments } from "@svar-ui/react-comments";
registerEditorItem("comments", Comments);
const users = [{ id: 1, name: "John Doe", avatar: "https://via.placeholder.com/150" }];
const items = [
{ comp: "comments", key: "comments", label: "Comments", users, activeUser: 1 }
];
const data = {
comments: [
{ id: 1, user: 1, content: "Greetings, fellow colleagues.", date: new Date() }
]
};
<Editor items={items} values={data} />
Full prop reference: Comments
DatePicker
A calendar-backed date input. Add clear: true for a button that unsets the value, and format to override the date string pattern for that field - it otherwise falls back to formats.dateFormat from the active locale.
import { Editor, registerEditorItem } from "@svar-ui/react-editor";
import { DatePicker } from "@svar-ui/react-core";
registerEditorItem("datepicker", DatePicker);
const items = [
{ comp: "datepicker", key: "deadline", label: "Deadline", clear: true }
];
<Editor items={items} />
Full prop reference: DatePicker
MultiCombo
The multi-select counterpart to Combo - same options shape, but the bound value is an array of ids. Set checkboxes: true to show a checkbox next to each option in the dropdown list.
import { Editor, registerEditorItem } from "@svar-ui/react-editor";
import { MultiCombo } from "@svar-ui/react-core";
registerEditorItem("multiselect", MultiCombo);
const users = [
{ id: 1, label: "Sarah Smith" },
{ id: 2, label: "Diego Redmoor" }
];
const items = [
{ comp: "multiselect", key: "users", label: "Users", checkboxes: true, options: users }
];
<Editor items={items} />
Full prop reference: MultiCombo
RichSelect
A single-select dropdown for picking from a predefined list. Give it an options array of { id, label } pairs to resolve a stored id to a display label; add clear: true to let users unset the value once one is picked.
import { Editor, registerEditorItem } from "@svar-ui/react-editor";
import { RichSelect } from "@svar-ui/react-core";
registerEditorItem("select", RichSelect);
const items = [
{
comp: "select",
key: "priority",
label: "Priority",
clear: true,
options: [
{ id: 1, label: "High" },
{ id: 2, label: "Medium" },
{ id: 3, label: "Low" }
]
}
];
<Editor items={items} />
Full prop reference: RichSelect
Slider
A numeric range input. min, max, and step shape the range - for a 0-1 progress value stepped by 10%, for example:
import { Editor, registerEditorItem } from "@svar-ui/react-editor";
import { Slider } from "@svar-ui/react-core";
registerEditorItem("slider", Slider);
const items = [
{ comp: "slider", key: "progress", label: "Progress", min: 0, max: 1, step: 0.1 }
];
<Editor items={items} />
Full prop reference: Slider
TaskList
TaskList comes from @svar-ui/react-tasklist and also manages array-shaped data - a checklist of { id, content, status } entries, where status is 0 for open and 1 for done.
import { Editor, registerEditorItem } from "@svar-ui/react-editor";
import { TaskList } from "@svar-ui/react-tasklist";
registerEditorItem("tasks", TaskList);
const items = [{ comp: "tasks", key: "task", label: "Task" }];
const data = {
task: [{ id: 1, content: "Task 1", status: 1 }]
};
<Editor items={items} values={data} />
Full prop reference: Tasklist

TinyMCE
Also bundled with the editor, TinyMCE renders a WYSIWYG rich text field. Same fill: true pattern as CodeMirror to stretch it across the available height (see full-height single field):
import { Editor, registerEditorItem, TinyMCE } from "@svar-ui/react-editor";
registerEditorItem("tinymce", TinyMCE);
const items = [
{ comp: "tinymce", key: "content", label: "Content", fill: true }
];
<Editor items={items} />

Custom Controls
Any React component can become an editor control - built-in and SVAR Core controls all implement the same minimal interface: receive the field's current value through a value prop, and report changes by calling an onChange prop with the new value. A custom five-star rating control, for example:
// Rating.jsx
function Rating({ value = 0, onChange }) {
return (
<div className="rating">
{[1, 2, 3, 4, 5].map(star => (
<button
key={star}
className={star <= value ? "filled" : ""}
onClick={() => onChange({ value: star })}
>
★
</button>
))}
</div>
);
}
export default Rating;
Register and use it exactly like any other control:
import { Editor, registerEditorItem } from "@svar-ui/react-editor";
import Rating from "./Rating.jsx";
registerEditorItem("rating", Rating);
const items = [{ comp: "rating", key: "rating", label: "Rating" }];
const values = { rating: 3 };
<Editor items={items} values={values} />
Multi-field Controls
A control isn't limited to editing a single value. Add a keys array to an item and the editor collects those fields from values into one object, passing it to your component as value; on onChange, it spreads the updated object back across the same keys. This is how you wire in a component that edits several related fields together - a date range with an all-day toggle, for example:
// EventDates.jsx
import { DatePicker, Switch } from "@svar-ui/react-core";
function EventDates({ value, onChange }) {
const update = part => onChange({ value: { ...value, ...part } });
return (
<>
<DatePicker value={value.start} onChange={ev => update({ start: ev.value })} />
<DatePicker value={value.end} onChange={ev => update({ end: ev.value })} />
<Switch value={value.isFullDay} onChange={ev => update({ isFullDay: ev.value })} />
</>
);
}
export default EventDates;
value here is not the raw field value but an object assembled from keys, so the component receives { start, end, isFullDay } and updates one or more of those fields at a time:
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"
}
];
const values = {
name: "Project kickoff",
start: new Date(2026, 5, 10, 9),
end: new Date(2026, 5, 10, 11),
isFullDay: false
};
<Editor items={items} values={values} />