morphos/react-schema-editor is a lightweight, customizable React JSON Schema editor for applications where users
need to create or maintain schemas visually.
The editor manages JSON Schema state and editing behavior without imposing a page layout or component library. Its
default UI is plain HTML, every structural part can be replaced through the components prop, and optional Bootstrap
3.4 and 5.3 component sets are available when those styles already fit your application.
Use it to:
- build source and destination schemas for data mapping, imports, exports, and API payloads;
- embed schema editing in an existing form, settings page, drawer, or modal workflow;
- keep the schema controlled in React and receive the complete JSON Schema after each change;
- replace individual controls or the complete nested-property layout with application-owned components.
Try the schema editor in the source and destination panels of the interactive playground.
React is an optional peer dependency of morphos:
npm install morphos react react-domImporting morphos/react-schema-editor does not require Bootstrap or another UI framework.
import { useState } from 'react';
import { SchemaEditor, type JsonSchema } from 'morphos/react-schema-editor';
const initialSchema: JsonSchema = {
type: 'object',
properties: {
invoiceNumber: { type: 'string' },
totalAmount: { type: 'number' },
billTo: {
type: 'object',
properties: {
name: { type: 'string' }
}
}
},
required: ['invoiceNumber']
};
function InvoiceSchemaEditor() {
const [schema, setSchema] = useState<JsonSchema>(initialSchema);
return <SchemaEditor value={schema} onChange={setSchema} />;
}onChange receives the complete current schema, so the same state can drive validation, previews, persistence, or a
MappingEditor.
For an uncontrolled editor, pass defaultValue instead. The current value remains available through the editor ref.
The editor is intentionally headless at its structural boundaries. It supplies ready-to-render controls and nested content, while your components decide where and how they appear.
For example, replace the default inline nested-properties section with your application's dialog components:
import type { SectionProps } from 'morphos/react-schema-editor';
import { Dialog, DialogContent, DialogTrigger } from './ui/Dialog';
function NestedPropertiesDialog({ children }: SectionProps) {
return (
<Dialog>
<DialogTrigger>Edit nested properties</DialogTrigger>
<DialogContent>{children}</DialogContent>
</Dialog>
);
}
const components = { Section: NestedPropertiesDialog };
<SchemaEditor
value={schema}
onChange={setSchema}
components={components}
/>The schema editor still owns property creation, removal, type changes, required flags, and nested state. The injected component only changes presentation. The same pattern works with drawers, popovers, tabs, accordion panels, and your design system's form controls.
Built-in defaults render plain HTML with dm-schema-editor-* class hooks. Style those classes directly or replace only
the slots that need application-specific behavior.
import { SchemaEditor, type TextInputProps } from 'morphos/react-schema-editor';
const TextInput = ({ value, onChange, placeholder, readOnly }: TextInputProps) => (
<input
className="app-input"
value={value}
onChange={event => onChange(event.target.value)}
placeholder={placeholder}
readOnly={readOnly}
/>
);
const components = { TextInput };
<SchemaEditor components={components} />Bootstrap integrations only emit classes; the corresponding Bootstrap CSS remains under your application's control.
import bootstrap34 from 'morphos/react-schema-editor/bootstrap34';
import bootstrap53 from 'morphos/react-schema-editor/bootstrap53';
<SchemaEditor components={bootstrap53} />Individual themed components are exported when you want to combine a theme with custom slots:
import { Row, TextFieldSetting } from 'morphos/react-schema-editor/bootstrap53';The editor supports:
- object properties and required flags;
- strings, numbers, integers, booleans, objects, and arrays;
- nested objects and array item schemas;
- nullable fields, titles, descriptions, formats, enums, and examples;
- numeric, string, array, and object constraints exposed by the selected field type;
- controlled, uncontrolled, read-only, and root-hidden rendering.
String formats and enums appear as recognizable options in the type selector. Enum and example values use one value per line in their default textarea editors.
<SchemaEditor
value={schema}
onChange={setSchema}
hideRootElement
exposeTitle
exposeDescription
readOnly
components={components}
labels={labels}
/>| Prop | Type | Description |
|---|---|---|
value |
JsonSchema |
Controlled schema value. |
defaultValue |
JsonSchema |
Uncontrolled initial value, used once on mount. |
onChange |
(next: JsonSchema) => void |
Receives the complete schema after each edit. |
hideRootElement |
boolean |
Renders only the root object's properties or root array's item editor. |
exposeTitle |
boolean |
Shows each field's title in its main row. |
exposeDescription |
boolean |
Shows each field's description in its main row. |
readOnly |
boolean |
Disables editing and suppresses onChange. |
components |
Partial<SchemaEditorComponents> |
Replaces any built-in UI slot. |
labels |
Partial<SchemaEditorLabels> |
Replaces any user-visible label. |
Use hideRootElement when the surrounding page already represents the root context. The root schema still comes from
value or defaultValue, including its type, properties, and items.
The component exposes this ref handle:
interface SchemaEditorHandle {
readonly value: JsonSchema;
}| Component | Purpose |
|---|---|
Container |
Wraps all rows at the current schema level. |
Row |
Places the field name, metadata, type, requirement, actions, and nested section. |
Section |
Places nested object properties or an array item editor. |
TextInput |
Edits property names and exposed text values. |
FieldLabel |
Renders read-only labels such as the root or array item name. |
TypeSelector |
Selects the schema type, format, or enum presentation. |
RequirementControl |
Changes whether an object property is required. |
SettingsButton |
Opens or closes field settings. |
SettingsGroup |
Places the expanded settings area. |
TextFieldSetting |
Edits text and numeric constraints. |
CheckboxFieldSetting |
Edits boolean settings such as nullable. |
TextareaFieldSetting |
Edits multi-line enum and example values. |
RemoveButton |
Removes a property. |
AddPropertyInput |
Creates a property at the current object level. |
Override SettingsGroup to move field settings into a custom panel or popover. Override Section to change how nested
schemas are navigated. Override Row when the complete field layout belongs to your design system.
Every visible string comes from SchemaEditorLabels. Override only the labels needed by the application:
const labels = {
addProperty: 'Add field',
propertyName: 'Field name',
removeProperty: 'Remove field'
};
<SchemaEditor labels={labels} />- Use
morphos/reactto visually build JSON-to-JSON mapping specifications from schemas. - Use the main
morphospackage to validate, store, and execute the resulting mappings.
