Skip to content

Fields from a JSON Schema ​

fieldsFromJsonSchema turns a JSON Schema object into a field list, so a form can be driven by the schema an API already publishes (an OpenAPI components.schemas entry, for example).

ts
import { fieldsFromJsonSchema } from '@dynamic-field-kit/core';

const { fields, defaults, warnings } = fieldsFromJsonSchema(
  {
    type: 'object',
    required: ['email'],
    properties: {
      email: { type: 'string', format: 'email' },
      age: { type: 'integer', minimum: 18 },
      plan: { enum: ['free', 'pro'], default: 'free' },
      contacts: {
        type: 'array',
        items: {
          type: 'object',
          properties: { phone: { type: 'string' } },
        },
      },
    },
  },
  { overrides: { 'contacts[].phone': { placeholder: '+84…' } } },
);
  • fields goes to MultiFieldInput / useDynamicForm like a hand-written list.
  • defaults holds the schema's default values, shaped like the form data. Pass it as the initial data.
  • warnings lists every property or keyword that did not make it into the form, with its path. Nothing is dropped silently.
SchemaField
stringtext; format picks email, date, time, datetime-local (date-time) or password
number, integernumber, with min / max from minimum / maximum and step from multipleOf (1 for an integer)
booleancheckbox
enum, or oneOf / anyOf made only of constselect; a const member's title is the option label
array of enumsselect with multiple
array of objectsrepeatable group, with minItems / maxItems and a defaultItem from the item defaults
nested objectsection, with the defaults of its properties as the section's default

title becomes the label (a readable form of the property name otherwise), description the description, readOnly a readOnlyCondition. required, minLength, maxLength, pattern, minimum, maximum and the email format become validate hooks built from validators, so their messages go through the form's message catalog. Local $ref (#/...), allOf, and nullable types (type: ['string', 'null'], or anyOf with a null branch) are followed.

Not turned into fields, and reported in warnings instead: objects without properties, tuples, arrays of free-form values, remote $ref, and exclusiveMinimum / exclusiveMaximum. Conditional keywords (if / then, dependentRequired) are ignored; express those with appearCondition through overrides.

overrides is keyed by the same path the warnings use and is merged over the generated field. Use it to choose an application-specific type (textarea, a custom picker), or to attach hooks a schema cannot express.

A JSON Schema from fields ​

fieldsToJsonSchema goes the other way: it describes the data a field list collects, for an API contract, a validator on the server, or documentation.

ts
import { fieldsToJsonSchema } from '@dynamic-field-kit/core';

const { schema, warnings } = fieldsToJsonSchema(fields, {
  title: 'Sign-up',
  defaults: { plan: 'free' },
  types: { rating: { type: 'integer', minimum: 1, maximum: 5 } },
  overrides: { username: { minLength: 3, pattern: '^[a-z]+$' } },
});
FieldSchema
text, textarea, search, tel, color, hiddenstring, with maxLength from props.maxLength
email, url, password, date, time, datetime-localstring with the matching format (uri, date-time)
number, rangenumber with minimum / maximum / multipleOf; integer when the step and minimum are whole
checkbox, switchboolean
select, radio, or any field with static optionsenum, or oneOf of const + title when a label differs from its value
the same with multiplearray of that, with uniqueItems
a repeatable group (fields)array of objects, with minItems / maxItems and the defaultItem values as defaults
a section (section)nested object, with its own properties and required; its defaults go to its properties

label becomes title, a string description the description, required the required list, and a field with computeValue is readOnly. defaults takes form data and records it as default; strict: true adds additionalProperties: false.

A schema cannot hold a function, so validate, appearCondition, readOnlyCondition and option loaders are listed in warnings rather than guessed at; put the rules they enforce in overrides, keyed by the same paths (username, contacts[].phone). A field type the kit does not know accepts any value until types describes it, and a file field is left out.

Released under the MIT License.