Documents
Studio writes this format for you. Every page and component you build in Studio is saved as one of these files — open Code mode to see the raw source of whatever document you have open.
A Jx document is a single
.json
file that describes one piece of user interface: its structure, its styling, the state it holds, and the behavior attached to it. The tree of JSON objects mirrors the DOM — the browser's own object model — so property names like
tagName
and
textContent
mean exactly what they mean to a browser. Simple documents are fully self-describing: no template language, no companion script file.
The smallest complete document:
{
"$schema": "https://jxsuite.com/schema/v1",
"$id": "Hello",
"state": { "name": "World" },
"tagName": "main",
"children": [{ "tagName": "h1", "textContent": "Hello, undefined!" }]
}
Root fields
Every document is a JSON object with up to six top-level fields:
| Field | Required | Description |
|---|---|---|
$schema |
Recommended | Schema the file is checked against — the dialect URI, or the project's generated bundle (below) |
$id |
Recommended | Component identifier, used by tooling |
$defs |
Optional | Pure JSON Schema type definitions — tooling only, never rendered |
state |
Optional | Reactive state: values, computed entries, functions, and data sources — see State |
tagName |
Required | HTML tag name for the root element |
children |
Optional | Array of child elements , text nodes, and repeaters , mixed freely |
Only
tagName
is required. A document can also carry
$media
(named breakpoints, see
Styling
) and
$elements
(custom-element dependencies, see
Components
).
https://jxsuite.com/schema/v1
names the dialect, which is what you want for a document that travels on its own. Inside a project, point
$schema
at the
document.schema.json
that
jx schema
writes into the project root instead. That bundle is the core schema
plus
every enabled extension's contributions, so your editor's autocomplete and
jx validate
are reading the same rules. See
Schema composition
.
The pointer is resolved relative to the file that carries it, so it needs one
../
per folder level:
"../document.schema.json"
from
pages/index.json
,
"../../document.schema.json"
from
pages/blog/post.json
. Too few and it points at a file that does not exist, which every validator reports as an unresolvable schema rather than as a document error.
$defs
— type definitions
$defs
holds pure JSON Schema 2020-12 type definitions. They exist for tooling — validation, autocomplete, Studio's input controls — and produce nothing at runtime:
{
"$defs": {
"Count": { "type": "integer", "minimum": 0, "maximum": 100 },
"Status": {
"type": "string",
"enum": ["idle", "loading", "success", "error"]
}
}
}
State entries reference these types with
$ref
(
{ "$ref": "#/$defs/Count" }
).
$defs
entries never contain
default
,
$prototype
, or template strings — runtime values belong in
state
.
Component or page fragment
What a document
is
follows from its root
tagName
and where the file lives:
A root
tagNamecontaining a hyphen ("my-counter","user-card") defines a custom element — a reusable component that other documents instantiate by reference.A root
tagNamethat is a plain HTML tag ("main","section") is a page fragment — a tree that renders in place, either as a route in a site'spages/directory (see Routing ) or inlined into another document via$ref(see References ).
Either kind may declare
state
; the difference is that a custom element gets its own isolated scope and a
$props
boundary (see
Props and scope
).
Why plain JSON
Jx documents are valid JSON — not JavaScript object literals, not JSX, not a template DSL. That distinction is load-bearing:
JSON serializes and deserializes without executing code.
There is no
thisambiguity — self-references are explicit$refpointers.Visual builders, IDEs, validators, and bundlers understand it natively.
JSON Schema tooling (validation, autocomplete, LSP) applies directly.
The format also follows the
rule of least power
: prefer a
$ref
binding over a template expression, a template expression over a
declarative expression
, and a handler
function
only when logic cannot be expressed otherwise.
How it works
Jx is a JSON Schema dialect: any 2020-12-compatible validator can check a document against the Jx meta-schema identified by
$schema
. In development, the runtime loads the
.json
file, builds a reactive scope from
state
, and renders the tree with real DOM calls. In production, the
build
compiles the JSON away — emitting plain JavaScript classes, static HTML, and extracted CSS.
Rules
A document must be valid JSON — no comments, no trailing commas, no inline code (behavior lives in
stateentries as strings or structured data).tagNameis the only required root field;$schemaand$idare recommended.$defsis tooling-only: no signals, no functions, no runtime artifacts.Jx reserves the keywords
$prototype,$props,$switch,$map,$src,$export,timing,default,body,arguments, andnameon top of the standard JSON Schema vocabulary.One document per file; a document nests other documents only by
$ref, never by pasting their JSON inline.
Related
Components — custom elements and the component model
Elements — the objects inside
childrenState — the four shapes of a
stateentryRouting — how documents in
pages/become URLsCode editing — the Studio surface for raw document source