JSON Schema rendering gallery

Comprehensive fixture page for visually reviewing the JsonSchemaFields renderer. Not part of the docs nav. Edit app/pages/dev/schema-gallery.vue to add cases.

Mode:

25 entries flagged as needs investigation — see amber-bordered cards below.

Primitives & basics

string

{
  "type": "string"
}
string

integer (mode-sensitive)

In javascript mode, renders as `number`.

{
  "type": "integer"
}
number

string + format: date-time

In javascript mode, renders as `Date` and the format chip is suppressed.

{
  "type": "string",
  "format": "date-time"
}
Date

string + format: email

{
  "type": "string",
  "format": "email"
}
string
formatemail

string + pattern (no format)

{
  "type": "string",
  "pattern": "^[a-z]+$"
}
string
pattern^[a-z]+$

string + format + pattern (pattern hidden)

{
  "type": "string",
  "format": "email",
  "pattern": "^[^@]+@[^@]+$"
}
string
formatemail

number with all numeric constraints

{
  "type": "number",
  "minimum": 0,
  "maximum": 100,
  "exclusiveMinimum": 0,
  "multipleOf": 5
}
number
min0max100min (exclusive)0multiple of5

bare {} (any value)

Empty schema — classified as `empty`.

{}

{ type: "null" }

{
  "type": "null"
}

{ type: "object" } (no properties)

needs investigation
{
  "type": "object"
}

Const & enum

const string

{
  "const": "fixed"
}
"fixed"

const number

{
  "const": 42
}
42

const wins over enum

{
  "const": "a",
  "enum": [
    "a",
    "b"
  ]
}
"a"

enum strings

{
  "enum": [
    "a",
    "b",
    "c"
  ]
}
"a" | "b" | "c"

enum mixed types

{
  "enum": [
    "on",
    "off",
    0,
    1
  ]
}
"on" | "off" | 0 | 1

Multi-type & nullable (review focus)

type: ["string", "null"]

needs investigation

Replaces the old `Array.isArray(schema.type)` workaround in `getTypeName`.

{
  "type": [
    "string",
    "null"
  ]
}
string | null

type: ["string", "number", "null"]

needs investigation

3-way join in the multi-type kind.

{
  "type": [
    "string",
    "number",
    "null"
  ]
}
string | number | null

OpenAPI nullable: true

needs investigation

Normalised by classify into multi-type as if `type: ["string","null"]`.

{
  "type": "string",
  "nullable": true
}
string | null

OpenAPI nullable + format: date-time

needs investigation

KNOWN GAP: javascript-mode format mapping (`Date | null`) is lost — multi-type ignores `format`.

{
  "type": "string",
  "format": "date-time",
  "nullable": true
}
string | null

multi-type as object property

needs investigation

Exercises the field-row code path.

{
  "type": "object",
  "properties": {
    "id": {
      "type": "string"
    },
    "middleName": {
      "type": [
        "string",
        "null"
      ]
    }
  },
  "required": [
    "id"
  ]
}
id
stringrequired
middleName
string | null

multi-type as array items

Should render as `(string | null)[]` — `needsParensInArrayContext` adds the parens.

{
  "type": "array",
  "items": {
    "type": [
      "string",
      "null"
    ]
  }
}
(string | null)[]

OpenAPI nullable on object

needs investigation

KNOWN GAP: classify's nullable branch only fires when `typeof type === "string"` — this stays `kind: "object"` and nullable is ignored.

{
  "type": "object",
  "id": "Foo",
  "properties": {
    "x": {
      "type": "string"
    }
  },
  "required": [
    "x"
  ],
  "nullable": true
}
object | null

Composition

allOf intersection

needs investigation
{
  "allOf": [
    {
      "id": "A",
      "type": "object",
      "properties": {
        "a": {
          "type": "string"
        }
      },
      "required": [
        "a"
      ]
    },
    {
      "id": "B",
      "type": "object",
      "properties": {
        "b": {
          "type": "number"
        }
      },
      "required": [
        "b"
      ]
    }
  ]
}
A & B

allOf single-element wrap

nuxt-component-meta sometimes emits this — should unwrap to plain `string`.

{
  "allOf": [
    {
      "type": "string"
    }
  ]
}
string

$ref to $defs (non-recursive)

Recursive $ref entries dropped — JsonSchemaFields recurses into resolved properties with `dereferenced: true`, but cyclic graphs lose the $defs context after the first deref.

{
  "$defs": {
    "Foo": {
      "id": "Foo",
      "type": "object",
      "properties": {
        "x": {
          "type": "string"
        }
      },
      "required": [
        "x"
      ]
    }
  },
  "$ref": "#/$defs/Foo"
}
x
stringrequired

Unions & discriminants

anonymous primitive union (string | number | null)

This is the shape canonical-types reflection actually produces — *not* multi-type.

{
  "anyOf": [
    {
      "type": "string"
    },
    {
      "type": "number"
    },
    {
      "type": "null"
    }
  ]
}
string | number | null

named union of objects (id: "Node")

When the union has an id, the field shows the id.

{
  "id": "Node",
  "anyOf": [
    {
      "id": "TextNode",
      "type": "object",
      "properties": {
        "type": {
          "const": "text"
        },
        "text": {
          "type": "string"
        }
      },
      "required": [
        "type",
        "text"
      ]
    },
    {
      "id": "ImageNode",
      "type": "object",
      "properties": {
        "type": {
          "const": "image"
        },
        "src": {
          "type": "string",
          "format": "uri"
        }
      },
      "required": [
        "type",
        "src"
      ]
    }
  ]
}

Accepts one of the following:

3-way named discriminated union (Media)

{
  "id": "Media",
  "anyOf": [
    {
      "id": "ImageNode",
      "type": "object",
      "properties": {
        "type": {
          "const": "image"
        },
        "src": {
          "type": "string",
          "format": "uri"
        }
      },
      "required": [
        "type",
        "src"
      ]
    },
    {
      "id": "Video",
      "type": "object",
      "properties": {
        "type": {
          "const": "video"
        },
        "src": {
          "type": "string",
          "format": "uri"
        }
      },
      "required": [
        "type",
        "src"
      ]
    },
    {
      "id": "FileNode",
      "type": "object",
      "properties": {
        "type": {
          "const": "file"
        },
        "href": {
          "type": "string",
          "format": "uri"
        },
        "mime": {
          "type": "string"
        }
      },
      "required": [
        "type",
        "href"
      ]
    }
  ]
}

Accepts one of the following:

mixed object + primitive (Foo | string)

needs investigation
{
  "anyOf": [
    {
      "id": "Foo",
      "type": "object",
      "properties": {
        "x": {
          "type": "string"
        }
      },
      "required": [
        "x"
      ]
    },
    {
      "type": "string"
    }
  ]
}
x
stringrequired

array of union ((A | B)[])

{
  "type": "array",
  "items": {
    "anyOf": [
      {
        "id": "TextNode",
        "type": "object",
        "properties": {
          "type": {
            "const": "text"
          },
          "text": {
            "type": "string"
          }
        },
        "required": [
          "type",
          "text"
        ]
      },
      {
        "id": "ImageNode",
        "type": "object",
        "properties": {
          "type": {
            "const": "image"
          },
          "src": {
            "type": "string",
            "format": "uri"
          }
        },
        "required": [
          "type",
          "src"
        ]
      }
    ]
  }
}
array

Accepts an array of the following:

anonymous discriminated tuples (Swatch-shape)

{
  "anyOf": [
    {
      "type": "array",
      "items": [
        {
          "const": "color"
        },
        {
          "type": "string"
        }
      ]
    },
    {
      "type": "array",
      "items": [
        {
          "const": "colors"
        },
        {
          "type": "array",
          "items": {
            "type": "string"
          }
        }
      ]
    },
    {
      "type": "array",
      "items": [
        {
          "const": "gradient"
        },
        {
          "type": "array",
          "items": {
            "type": "string"
          }
        }
      ]
    }
  ]
}

Accepts one of the following:

Literal unions

named clean alias (FallbackVariant)

Clean alias — always expands.

{
  "id": "FallbackVariant",
  "anyOf": [
    {
      "const": "icon"
    },
    {
      "const": "text"
    },
    {
      "const": "none"
    }
  ]
}

Accepts one of the following:

"icon""text""none"

joined-form long (4+ consts, no clean id)

{
  "id": "\"a\" | \"b\" | \"c\" | \"d\"",
  "anyOf": [
    {
      "const": "a"
    },
    {
      "const": "b"
    },
    {
      "const": "c"
    },
    {
      "const": "d"
    }
  ]
}

Accepts one of the following:

"a""b""c""d"

joined-form too short (2 consts)

Below the 4-const threshold — does not expand.

{
  "id": "\"a\" | \"b\"",
  "anyOf": [
    {
      "const": "a"
    },
    {
      "const": "b"
    }
  ]
}
"a" | "b"

named with primitive escape (IconName)

{
  "id": "IconName",
  "anyOf": [
    {
      "const": "arrow"
    },
    {
      "const": "check"
    },
    {
      "const": "close"
    },
    {
      "const": "menu"
    },
    {
      "const": "home"
    },
    {
      "type": "string"
    }
  ]
}

Accepts one of the following:

"arrow""check""close""menu""home"or anystring

multi-escape (string + number)

{
  "id": "Sized",
  "anyOf": [
    {
      "const": "s"
    },
    {
      "const": "m"
    },
    {
      "const": "l"
    },
    {
      "type": "string"
    },
    {
      "type": "number"
    }
  ]
}

Accepts one of the following:

"s""m""l"or anystring/number

numeric literal union

{
  "id": "PowerOfTwo",
  "anyOf": [
    {
      "const": 1
    },
    {
      "const": 2
    },
    {
      "const": 4
    },
    {
      "const": 8
    }
  ]
}

Accepts one of the following:

1248

mixed-type consts ("on" | "off" | 0 | 1)

{
  "anyOf": [
    {
      "const": "on"
    },
    {
      "const": "off"
    },
    {
      "const": 0
    },
    {
      "const": 1
    }
  ]
}
"on" | "off" | 0 | 1

boolean-const union (KNOWN GAP)

needs investigation

.todo line 581: clean alias should expand, currently collapses to `boolean`.

{
  "id": "Toggle",
  "anyOf": [
    {
      "const": true
    },
    {
      "const": false
    }
  ]
}

Accepts one of the following:

truefalse

Objects

simple { name, age? }

{
  "type": "object",
  "properties": {
    "name": {
      "type": "string"
    },
    "age": {
      "type": "integer"
    }
  },
  "required": [
    "name"
  ]
}
name
stringrequired
age
number

named object (id: "User")

{
  "id": "User",
  "type": "object",
  "properties": {
    "name": {
      "type": "string"
    },
    "email": {
      "type": "string",
      "format": "email"
    }
  },
  "required": [
    "name",
    "email"
  ]
}
name
stringrequired
email
stringrequired
formatemail

with deprecated property

{
  "type": "object",
  "properties": {
    "active": {
      "type": "boolean"
    },
    "legacy": {
      "type": "string",
      "deprecated": true
    }
  },
  "required": [
    "active"
  ]
}
active
booleanrequired
legacy
stringdeprecated

with default values

{
  "type": "object",
  "properties": {
    "greeting": {
      "type": "string",
      "default": "hello"
    },
    "retries": {
      "type": "integer",
      "default": 3
    }
  }
}
greeting
string
default"hello"
retries
number
default3

nested 3 levels

{
  "type": "object",
  "properties": {
    "a": {
      "type": "object",
      "properties": {
        "b": {
          "type": "object",
          "properties": {
            "c": {
              "type": "string"
            }
          },
          "required": [
            "c"
          ]
        }
      },
      "required": [
        "b"
      ]
    }
  },
  "required": [
    "a"
  ]
}

object whose property is multi-type

needs investigation
{
  "type": "object",
  "id": "Profile",
  "properties": {
    "displayName": {
      "type": "string"
    },
    "middleName": {
      "type": [
        "string",
        "null"
      ]
    },
    "age": {
      "type": "integer",
      "nullable": true
    }
  },
  "required": [
    "displayName"
  ]
}
displayName
stringrequired
middleName
string | null
age
integer | null

Records

Record<string, string>

In javascript mode renders as `Record<string, string>`.

{
  "type": "object",
  "additionalProperties": {
    "type": "string"
  }
}
Record<string, string>

Record<string, A | B>

needs investigation
{
  "type": "object",
  "additionalProperties": {
    "anyOf": [
      {
        "id": "TextNode",
        "type": "object",
        "properties": {
          "type": {
            "const": "text"
          },
          "text": {
            "type": "string"
          }
        },
        "required": [
          "type",
          "text"
        ]
      },
      {
        "id": "ImageNode",
        "type": "object",
        "properties": {
          "type": {
            "const": "image"
          },
          "src": {
            "type": "string",
            "format": "uri"
          }
        },
        "required": [
          "type",
          "src"
        ]
      }
    ]
  }
}
Record<string, TextNode | ImageNode>

CustomFields open record (named)

needs investigation
{
  "id": "CustomFields",
  "title": "CustomFields",
  "type": "object",
  "additionalProperties": {}
}
Record<string, unknown>

additionalProperties + siblings (KNOWN GAP)

needs investigation

.todo line 576: should render as object + "any other key" row. Currently `additionalProperties` is dropped because object branch wins.

{
  "type": "object",
  "properties": {
    "id": {
      "type": "string"
    }
  },
  "required": [
    "id"
  ],
  "additionalProperties": {
    "type": "number"
  }
}
id
stringrequired

Arrays

string[]

{
  "type": "array",
  "items": {
    "type": "string"
  }
}
string[]

string[] with min/max/unique

{
  "type": "array",
  "items": {
    "type": "string"
  },
  "minItems": 1,
  "maxItems": 10,
  "uniqueItems": true
}
string[]
min items1max items10unique itemstrue

(A | B)[] (parens needed)

{
  "type": "array",
  "items": {
    "anyOf": [
      {
        "type": "string"
      },
      {
        "type": "number"
      }
    ]
  }
}
array
string | number

(string & {})[]

needs investigation
{
  "type": "array",
  "items": {
    "allOf": [
      {
        "type": "string"
      },
      {
        "id": "Branded",
        "type": "object"
      }
    ]
  }
}
array
string & object

Foo[]-style with items description

needs investigation

Items description should appear above the expanded property list (`getVariantListDescriptionHtml`).

{
  "type": "array",
  "items": {
    "id": "Foo",
    "type": "object",
    "description": "A Foo represents a configurable thing in the system.",
    "properties": {
      "x": {
        "type": "string"
      }
    },
    "required": [
      "x"
    ]
  }
}
array
x
stringrequired

Tuples

3-tuple [string, number, boolean]

needs investigation
{
  "type": "array",
  "items": [
    {
      "type": "string"
    },
    {
      "type": "number"
    },
    {
      "type": "boolean"
    }
  ]
}
array

tuple with optional tail (minItems: 1)

needs investigation

Slot 2 should render as `number?`.

{
  "type": "array",
  "items": [
    {
      "type": "string"
    },
    {
      "type": "number"
    }
  ],
  "minItems": 1
}
array
min items1

discriminated 2-tuple [type: "colors", value: string[]]

needs investigation
{
  "type": "array",
  "items": [
    {
      "const": "colors"
    },
    {
      "type": "array",
      "items": {
        "type": "string"
      }
    }
  ]
}
array
type
"colors"required
value
string[]required

tuple with enum head

needs investigation
{
  "type": "array",
  "items": [
    {
      "enum": [
        "x",
        "y",
        "z"
      ]
    },
    {
      "type": "number"
    }
  ]
}
array

Description visibility rules

A. Property has description, schema has none

Description on the field row, always visible.

{
  "type": "object",
  "properties": {
    "foo": {
      "type": "string",
      "description": "A property-level description."
    }
  }
}
foo
string

A property-level description.

B. Property has description AND schema (object) has description

No property description here — when expandable & single-variant & variant.schema === field, `isFieldDescriptionFromObject` is true so the description shows only when expanded.

{
  "type": "object",
  "properties": {
    "foo": {
      "id": "Foo",
      "type": "object",
      "description": "Object-level description (only when expanded).",
      "properties": {
        "x": {
          "type": "string",
          "description": "Inner field description."
        }
      },
      "required": [
        "x"
      ]
    }
  }
}

C. Property w/o description, schema has description

Description appears only when expanded.

{
  "type": "object",
  "properties": {
    "user": {
      "id": "User",
      "type": "object",
      "description": "A registered user account.",
      "properties": {
        "name": {
          "type": "string"
        },
        "email": {
          "type": "string",
          "format": "email"
        }
      },
      "required": [
        "name",
        "email"
      ]
    }
  }
}

D. `Foo[]` field where items has description

Items description renders above the expanded property list (`getVariantListDescriptionHtml`).

{
  "type": "object",
  "properties": {
    "items": {
      "type": "array",
      "items": {
        "id": "Item",
        "type": "object",
        "description": "A line item in the cart.",
        "properties": {
          "sku": {
            "type": "string"
          },
          "qty": {
            "type": "integer"
          }
        },
        "required": [
          "sku",
          "qty"
        ]
      }
    }
  }
}

E. `Foo[]` where property AND items have descriptions

Property description on field row; items description above the expanded list.

{
  "type": "object",
  "properties": {
    "lineItems": {
      "type": "array",
      "description": "Cart line items.",
      "items": {
        "id": "LineItem",
        "type": "object",
        "description": "A LineItem describes a single product entry.",
        "properties": {
          "sku": {
            "type": "string"
          },
          "qty": {
            "type": "integer"
          }
        },
        "required": [
          "sku",
          "qty"
        ]
      }
    }
  }
}

F. Union of objects, each variant with its own description

Per-variant descriptions render in JsonSchemaVariantList rows.

{
  "type": "object",
  "properties": {
    "node": {
      "anyOf": [
        {
          "id": "TextNode",
          "type": "object",
          "description": "A leaf node containing inline text.",
          "properties": {
            "type": {
              "const": "text"
            },
            "text": {
              "type": "string"
            }
          },
          "required": [
            "type",
            "text"
          ]
        },
        {
          "id": "ImageNode",
          "type": "object",
          "description": "A leaf node containing an image source URL.",
          "properties": {
            "type": {
              "const": "image"
            },
            "src": {
              "type": "string",
              "format": "uri"
            }
          },
          "required": [
            "type",
            "src"
          ]
        }
      ]
    }
  }
}

G. Variant with id and a different title

needs investigation

Each variant row prefixes the description with bolded title (when title differs from id).

{
  "type": "object",
  "properties": {
    "kind": {
      "id": "Kind",
      "title": "A human-readable kind label",
      "description": "Distinguishes between supported kinds.",
      "anyOf": [
        {
          "id": "Alpha",
          "title": "Alpha (priority A)",
          "description": "Highest priority routing.",
          "type": "object",
          "properties": {
            "tag": {
              "const": "alpha"
            }
          },
          "required": [
            "tag"
          ]
        },
        {
          "id": "Beta",
          "title": "Beta (priority B)",
          "description": "Standard routing.",
          "type": "object",
          "properties": {
            "tag": {
              "const": "beta"
            }
          },
          "required": [
            "tag"
          ]
        }
      ]
    }
  }
}

Opaque & real-world shapes

Opaque component (id + title, no type)

{
  "id": "Component",
  "title": "Component"
}
Component

LinkQueryValue (anonymous string | number | null)

{
  "anyOf": [
    {
      "type": "string"
    },
    {
      "type": "number"
    },
    {
      "type": "null"
    }
  ]
}
string | number | null

CustomFields open record

{
  "id": "CustomFields",
  "title": "CustomFields",
  "type": "object",
  "additionalProperties": {}
}
Record<string, unknown>

Annotations chips on a string field

{
  "type": "string",
  "readOnly": true,
  "default": "hello",
  "minLength": 1,
  "maxLength": 32
}
string
min length1max length32read-onlydefault"hello"

write-only & deprecated together

{
  "type": "string",
  "writeOnly": true,
  "deprecated": true
}
string
write-only

Known gaps (visualized)

schema boolean `true` as property

needs investigation

.todo line 570: spec says `true` means "any value". Currently passes through unchanged.

{
  "type": "object",
  "properties": {
    "anything": true
  }
}

Draft-4 exclusiveMinimum: true (boolean form)

needs investigation

.todo line 578: currently emits chip with value `"true"` instead of falling back to `minimum`.

{
  "type": "number",
  "minimum": 0,
  "exclusiveMinimum": true
}
number
min0min (exclusive)true

if/then/else conditional

needs investigation

.todo line 573: conditional schemas are ignored.

{
  "type": "object",
  "properties": {
    "kind": {
      "type": "string"
    }
  },
  "if": {
    "properties": {
      "kind": {
        "const": "a"
      }
    }
  },
  "then": {
    "required": [
      "extraA"
    ]
  },
  "else": {
    "required": [
      "extraB"
    ]
  }
}
kind
string

not

needs investigation

.todo line 574: `not` is ignored.

{
  "not": {
    "type": "string"
  }
}
unknown
Copyright © 2026 Laioutr GmbH