JSON Schema Forms
Add $schema to your data. Get a free edit form.
How it works
Add a $schema property to your JSON-LD data pointing to a JSON Schema file:
{
"@context": { "title": "http://purl.org/dc/terms/title" },
"@id": "#this",
"@type": "Tracker",
"$schema": "my-schema.json",
"title": "My Tasks"
}
Include the schema pane in your HTML:
<script type="module" data-pane src="panes/schema-pane.js"></script>
That's it. An "Edit" tab appears with auto-generated form fields.
What gets generated
| Schema type | Form element |
|---|---|
string | Text input |
string with long maxLength | Textarea |
number / integer | Number input with min/max |
boolean | Checkbox |
enum | Dropdown select |
array of objects | Repeatable fieldset with add/remove |
Properties starting with @ or $ are hidden from the form.
Validation
Fields are validated as you type:
required— shows red asterisk, error on emptyminLength/maxLength— character count validationminimum/maximum— number range validationpattern— regex validation
Errors show inline under the field. The store still saves — validation is advisory, not blocking.
Example schema
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "My App",
"description": "Edit your app data",
"type": "object",
"required": ["title"],
"properties": {
"title": {
"type": "string",
"minLength": 1,
"description": "The name of your app"
},
"status": {
"type": "string",
"enum": ["draft", "published", "archived"],
"description": "Current status"
},
"priority": {
"type": "integer",
"minimum": 1,
"maximum": 5,
"description": "Priority level"
},
"published": {
"type": "boolean",
"description": "Whether this is public"
},
"items": {
"type": "array",
"title": "Items",
"description": "List of items",
"items": {
"type": "object",
"properties": {
"@id": { "type": "string" },
"@type": { "const": "Item" },
"name": { "type": "string", "description": "Item name" },
"done": { "type": "boolean" }
}
}
}
}
}
$ref support
The schema pane resolves $ref pointers to $defs and definitions:
{
"properties": {
"items": {
"type": "array",
"items": { "$ref": "#/$defs/item" }
}
},
"$defs": {
"item": {
"type": "object",
"properties": {
"name": { "type": "string" },
"status": { "type": "string", "enum": ["todo", "done"] }
}
}
}
}
Schema URL resolution
The $schema URL is resolved relative to the data file, not the page. So if your data is at data/tasks.jsonld with "$schema": "tasks-schema.json", the pane fetches data/tasks-schema.json.
Completely optional
The schema pane is opt-in at two levels:
- App level — only loads if you include
<script data-pane src="panes/schema-pane.js"> - Data level — only shows a tab if the data has
$schema
No $schema in the data? No tab. No schema pane in the HTML? No effect. Zero impact on apps that don't use it.
Live demo
See it in action: losos.org/todo/ — click the "Edit" tab. The form is generated from todo-schema.json.