Schema Reference
The schema is a JSON Schema document that describes the shape of the data your form collects. JSON Forms uses the schema both to pick an appropriate renderer for each property and to validate what customers enter.
This page is a practical tour of JSON Schema as applied to JSON Forms in Prismatic. It covers the types, keywords, and patterns you'll reach for most often, along with notes on how each one influences the generated form. The JSON Schema specification is authoritative for any keyword that isn't called out here.
Top-level shape
A JSON Forms schema is almost always an object with a properties map:
{
"type": "object",
"properties": {
"companyName": { "type": "string" },
"numEmployees": { "type": "integer" }
},
"required": ["companyName"]
}
The top-level type can also be "array" when the entire form collects a list of items.
Supported types
type | Default renderer | Notes |
|---|---|---|
string | Text input | See formats for date, time, password, and so on |
integer | Number input | Whole numbers only |
number | Number input | Decimal numbers |
boolean | Checkbox | Set options.toggle on the UI schema element to render as a switch |
object | Nested group | Typically used to compose form sections |
array | Table layout | Array of objects; Prismatic defaults to a table layout |
See the renderers reference for a complete type-to-renderer mapping.
Nested objects
Objects nest inside other objects with their own properties and required arrays.
The generated form data preserves the shape exactly - if the schema has a company object with name and headcount properties, the form data will have a company object with name and headcount properties:
{
"type": "object",
"properties": {
"company": {
"type": "object",
"properties": {
"name": { "type": "string" },
"headcount": { "type": "integer" }
},
"required": ["name"]
}
}
}
Nested objects render inline inside their parent layout by default.
Wrap them in a Group in the UI schema to add a visible label and container.
For shapes reused in more than one place, see References with $ref.
Formats
Set format on a string property to pick a specialized renderer, a validator, or both.
Prismatic supports these formats:
date
Renderer: Date picker
Accepted values: ISO 8601 date strings in YYYY-MM-DD form, such as 2026-04-21.
Use with formatMinimum and formatMaximum to constrain the selectable range.
time
Renderer: Time picker
Accepted values: ISO 8601 time strings in HH:mm:ss form, such as 14:30:00.
Fractional seconds (HH:mm:ss.sss) and an optional timezone suffix (Z or ±HH:mm) are also accepted.
date-time
Renderer: Date-and-time picker
Accepted values: Full ISO 8601 timestamps combining a date and time with a T separator and a timezone suffix, such as 2026-04-21T14:30:00Z.
password
Renderer: Masked text input
Accepted values: Any string. This format affects presentation only - it does not validate content.
email
Renderer: Text input
Accepted values: A standard email address in local-part@domain form, such as alex@example.com.
uri
Renderer: Text input
Accepted values: An absolute URI that includes a scheme, such as https://example.com/widgets/42.
Relative URIs are rejected.
ipv4
Renderer: Text input
Accepted values: Four dot-separated integers from 0 to 255, such as 192.0.2.1.
Example
{
"type": "object",
"properties": {
"startDate": { "type": "string", "format": "date" },
"apiKey": { "type": "string", "format": "password" }
}
}
Validation keywords
Prismatic validates user input against the standard JSON Schema validation keywords. The following are the ones you'll use most often:
| Keyword | Applies to | Description |
|---|---|---|
required | object | Array of property names that must be present |
minLength / maxLength | string | Minimum and maximum string length |
pattern | string | Regular expression the input must match |
minimum / maximum | integer, number | Numeric bounds |
exclusiveMinimum / exclusiveMaximum | integer, number | Exclusive numeric bounds |
multipleOf | integer, number | Value must be a multiple of this number |
formatMinimum / formatMaximum | string with format | Inclusive bounds for date, time, and date-time formats |
formatExclusiveMinimum / formatExclusiveMaximum | string with format | Exclusive bounds for date, time, and date-time formats |
minItems / maxItems | array | Bounds on the number of items |
uniqueItems | array | When true, all items must be unique |
Validation runs continuously as the customer types. You can change when errors display with the Validation Mode setting on the config variable - see Validation mode.
For validation that the schema alone can't express, see JSON Form Validation.
Default values and pre-filling the form
To pre-fill a form with initial values, return a data property alongside schema and uiSchema from your data source:
{
"schema": {
/* ... */
},
"uiSchema": {
/* ... */
},
"data": {
"region": "us-east-1",
"retryCount": 3,
"enableCache": true
}
}
See Pre-filling forms with default data for the full pattern.
The schema's default keyword is an annotation - it describes what a property's default value would be, but doesn't pre-populate the form.
Return data from your data source whenever you want the form to open with values already filled in.
Fixed values with const
const asserts that a property holds a specific value.
Its primary use in JSON Forms is inside a oneOf array to build dropdowns where the displayed label and the stored value differ:
{
"continent": {
"type": "string",
"oneOf": [
{ "title": "North America", "const": "NA" },
{ "title": "Europe", "const": "EU" }
]
}
}
See Dropdowns with enum and oneOf for the full pattern.
Dropdowns with enum and oneOf
Two schema patterns produce dropdown menus:
enum- a flat array of string values. The customer sees the same value that the config variable stores.oneOf- an array of{ "title": ..., "const": ... }objects. The customer sees thetitle; the config variable stores theconst.
{
"continent": {
"type": "string",
"enum": ["North America", "Europe", "Asia"]
}
}
{
"continent": {
"type": "string",
"oneOf": [
{ "title": "North America", "const": "NA" },
{ "title": "Europe", "const": "EU" },
{ "title": "Asia", "const": "AS" }
]
}
}
Use oneOf whenever the display label and stored value need to differ, or when you're populating the list from a third-party API and want to store a stable ID.
Add options.autocomplete: true to the UI schema element to render a oneOf dropdown as a type-ahead.
Arrays
Arrays let the customer add one or more items with the same structure:
{
"type": "array",
"items": {
"type": "object",
"properties": {
"channel": { "type": "string" },
"notification": { "type": "string", "enum": ["Created", "Updated"] }
},
"required": ["channel", "notification"]
}
}
By default, arrays render as a table.
Use options.layout to switch to an accordion instead, or use the ListWithDetail UI type for a master-detail layout.
minItems, maxItems, and uniqueItems apply to the array itself.
Validation keywords on items apply to each array entry.
References with $ref
Prismatic resolves every $ref in your schema before rendering the form.
This lets you reuse subschemas without worrying about whether a specific renderer resolves references on its own.
{
"type": "object",
"definitions": {
"address": {
"type": "object",
"properties": {
"street": { "type": "string" },
"city": { "type": "string" }
},
"required": ["street", "city"]
}
},
"properties": {
"billing": { "$ref": "#/definitions/address" },
"shipping": { "$ref": "#/definitions/address" }
}
}
Descriptions and titles
Both description and title on a property surface in the UI:
descriptionappears as helper text beneath the input.titleoverrides the auto-generated label (otherwise derived from the property name).
The UI schema's label takes precedence over the schema's title when both are set.
Descriptions show even when the input is not focused unless you set options.showUnfocusedDescription: false.
Required fields
Mark required fields in the parent object's required array, not on the field itself:
{
"type": "object",
"properties": {
"companyName": { "type": "string" },
"companyDescription": { "type": "string" }
},
"required": ["companyName"]
}
Required fields display an asterisk next to their label.
Set options.hideRequiredAsterisk: true on a control or layout to suppress the asterisk for that element.
Composing schemas with allOf, anyOf, oneOf, and not
The composition keywords let you validate against multiple subschemas and pull properties from them into the form.
JSON Forms walks into these subschemas when a UI schema control scopes a property defined inside one of them, so a property declared inside an allOf branch renders just like a top-level property would:
{
"type": "object",
"allOf": [
{
"properties": {
"accountId": { "type": "string" }
}
}
],
"properties": {
"accountName": { "type": "string" }
}
}
{
"type": "VerticalLayout",
"elements": [
{ "type": "Control", "scope": "#/properties/accountName" },
{ "type": "Control", "scope": "#/properties/accountId" }
]
}
Both controls render, and customer input for accountId flows into the form data as expected.
| Keyword | Validation | Renders properties from the subschema? |
|---|---|---|
allOf | Yes | Yes - scope controls to #/properties/<name> and the property resolves. |
anyOf | Yes | Yes - same resolution as allOf. |
oneOf | Yes | Yes for full subschemas and in the dropdown pattern ({ "title", "const" } entries on a string property). |
not | Yes | Not applicable - not forbids a shape and doesn't contribute properties. Most useful inside UI rule conditions. |
Keep in mind: JSON Forms renders every control the UI schema declares regardless of whether the condition's data matches. Composition keywords influence validation, not visibility. For show/hide behavior, use UI rules.
For example, not inside a rule condition expresses "show this element when the country is anything other than the US":
{
"rule": {
"effect": "SHOW",
"condition": {
"scope": "#/properties/country",
"schema": {
"not": { "const": "United States" }
}
}
}
}
Conditional validation with if / then / else
if / then / else lets you apply different validation rules depending on the form data:
{
"type": "object",
"properties": {
"tier": { "type": "string", "enum": ["free", "paid"] },
"promoCode": { "type": "string" }
},
"if": { "properties": { "tier": { "const": "paid" } } },
"then": { "required": ["promoCode"] }
}
Properties declared inside then or else subschemas resolve the same way allOf properties do - scope a control to #/properties/<name> and it renders.
What if / then / else doesn't do is hide controls based on the condition; every control the UI schema declares stays visible.
For conditional visibility, use UI rules instead.
Keywords Prismatic handles differently
A few JSON Schema keywords are worth calling out because their effect on the form isn't obvious:
additionalProperties- Prismatic only renders controls for properties you declare inproperties(or reach through composition keywords), so schema-leveladditionalProperties: falsedoesn't change the UI. AJV still enforces it during validation when the form data contains keys the schema doesn't cover.readOnly- schema-levelreadOnly: truedisables the input control, so the customer can see the value but not edit it. You can also setoptions.readonlyon a UI schema element to apply the same effect, including to layouts so an entire group becomes non-editable.writeOnly- Prismatic doesn't usewriteOnlyas a rendering hint. If you need a masked input, use"format": "password"instead.