ObjectUIObjectUI
Fields

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

{
  "status": 200,
  "data": {
    "id": 123,
    "name": "Test"
  }
}

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

  1. Use for Flexible Data: When schema changes frequently
  2. Validate on Backend: Always validate structure server-side
  3. Consider Alternatives: Use typed fields when structure is fixed
  4. Document Schema: Provide clear documentation for expected structure
  5. 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.

On this page