Object Field
JSON object editor for structured data
The Object Field component provides a JSON editor for storing and editing structured data objects. It validates JSON syntax and provides a textarea interface for complex data.
It is the form editor for the free-form JSON field types: object, composite, record and json all resolve to it. A json value need not be an object — an array, a number, a string, a boolean or null is shown as its JSON text and parsed back as itself. (code is a different field: it stays a raw-text editor and saves its text.)
Basic Usage
Basic Object Editor
Structured Configuration
Structured Configuration
Nested Data
Nested Object Data
Read-Only
Read Only Json Display
Field Schema
A JSON field is authored as ObjectFieldMetadata (@object-ui/types), which is the
source of truth for the key set. Its type value is json, the @objectstack/spec
FieldType for a free-form JSON value: object is not a spec field type, and
FieldSchema refuses it at type. The type adds no key of its own to
BaseFieldMetadata; the shape the value must have is declared on the object instead
(see Schema Validation).
import type { ObjectFieldMetadata } from '@object-ui/types';
const settings: ObjectFieldMetadata = {
type: 'json',
name: 'settings',
label: 'Settings',
placeholder: '{ }',
inlineHelpText: 'Stored as JSON.',
};The value being edited, and the className / disabled a host supplies, are not
metadata keys — they are runtime widget props. See Field Widget Props.
JSON Validation
The field validates JSON syntax in real-time:
- Valid JSON: Updates the value immediately
- Invalid JSON: Refused. The text stays in the box so it can be corrected, the box says "Invalid JSON" and is marked invalid, and the value is not updated. Inside a form the box is also invalid for the browser's constraint validation, so the form will not submit until the text parses — the last valid value is never sent in its place.
- Empty Input: Sets value to
null
Data Format
The object field stores data as parsed JSON:
// Input (string)
'{"name": "John", "age": 30}'
// Stored (object)
{ name: "John", age: 30 }
// Display (formatted)
{
"name": "John",
"age": 30
}Common Patterns
Configuration Objects
{
type: 'json',
name: 'api_config',
label: 'API Configuration',
value: {
endpoint: 'https://api.example.com',
timeout: 5000,
retries: 3,
headers: {
'Content-Type': 'application/json'
}
}
}Metadata
{
type: 'json',
name: 'custom_metadata',
label: 'Custom Metadata',
value: {
tags: ['important', 'urgent'],
priority: 'high',
department: 'engineering'
}
}Preferences
{
type: 'json',
name: 'user_preferences',
label: 'Preferences',
value: {
theme: 'dark',
language: 'en',
notifications: {
email: true,
push: false,
sms: false
}
}
}Cell Renderer
In tables/grids, a json value is rendered by the JSON cell renderer —
getCellRenderer('json') resolves to it, as getCellRenderer('object') does:
import { JsonCellRenderer } from '@object-ui/fields';
// <JsonCellRenderer value={specs} field={field} /> renders single-line JSON,
// truncated to the column width with the full text in the cell's `title`.
// A null or empty value renders an em-dash instead.composite and record values are not drawn as JSON. Their cell — in a grid and
on the record page alike — is one line of labelled sub-values, with the full text
in the title:
// composite { width: 10, height: 20 }
Width 10 · Height 20
// record { primary: { name: "A", score: 9 }, backup: { name: "B", score: 7 } }
Primary (Name A · Score 9) · Backup (Name B · Score 7)A label is the humanized key: the field metadata declares no sub-fields to take a
label from. A number sub-value is formatted as the number cell formats it, a boolean
reads as Yes / No in the reader's language, a string reads as itself, and an object or
an array nested inside a sub-value stays compact JSON.
An empty value, [], {} and a non-object value read as the JSON cell reads them.
Schema Validation
The shape a JSON value must have is declared on the object, not on the field.
@objectstack/spec has a validation rule for exactly this, type: 'json_schema', which
names the field and carries a JSON Schema document. Like every object validation rule it
runs on the server's write path, on the writes its events name. FieldSchema has no
field-level schema key: it refuses one
by name, and ObjectFieldMetadata refuses it at compile time.
// on the object definition
validations: [
{
type: 'json_schema',
name: 'product_specs_shape',
field: 'product_specs',
message: 'Product specifications are not in the expected shape.',
schema: {
type: 'object',
properties: {
weight: { type: 'number' },
dimensions: {
type: 'object',
properties: {
width: { type: 'number' },
height: { type: 'number' },
depth: { type: 'number' }
}
},
materials: { type: 'array' }
}
}
}
]Use Cases
- Configuration: Application settings, API configurations
- Metadata: Custom properties, tags, attributes
- API Responses: Storing API response data
- Preferences: User preferences, feature flags
- Structured Data: Any complex structured information
- JSON Storage: Raw JSON data storage
Best Practices
- Use for Flexible Data: When schema changes frequently
- Validate on Backend: Always validate structure server-side
- Consider Alternatives: Use typed fields when structure is fixed
- Document Schema: Provide clear documentation for expected structure
- Size Limits: Set reasonable size limits for JSON data
Backend Validation
ObjectUI does not check the shape of a JSON value. ObjectField checks JSON syntax
only — it accepts any value JSON.parse accepts, and refuses a draft it cannot parse —
so nothing on the client rejects a well-formed object whose shape is wrong. Shape
validation belongs on the server, and the object's json_schema rule above is how it is
declared there.