export const metadata = { title: "Specs" }
# Specs
A spec is a JSON document that describes your UI.
## What is a Spec?
A spec (specification) is the actual JSON that describes a UI. It conforms to a [schema](/docs/schemas) and uses components from a [catalog](/docs/catalog). Specs can be:
- Generated by AI in real-time
- Stored in a database
- Streamed progressively from a server
- Hand-authored as JSON files
json-render is schema-agnostic — your specs can follow any JSON structure you choose.
## Example Specs
### Simple Spec
A basic spec using the `@json-render/react` schema. Note the flat structure with a `root` key and `elements` map:
```json
{
"root": "card-1",
"elements": {
"card-1": {
"type": "Card",
"props": { "title": "Welcome" },
"children": ["text-1"]
},
"text-1": {
"type": "Text",
"props": { "content": "Hello, $data.user.name!" },
"children": []
}
}
}
```
### Complex Spec
A more complex spec with multiple nested elements:
```json
{
"root": "card-1",
"elements": {
"card-1": {
"type": "Card",
"props": { "title": "User Profile", "padding": "md" },
"children": ["row-1", "button-1"]
},
"row-1": {
"type": "Row",
"props": { "gap": "md" },
"children": ["avatar-1", "stack-1"]
},
"avatar-1": {
"type": "Avatar",
"props": { "src": "$data.user.avatar", "alt": "$data.user.name" },
"children": []
},
"stack-1": {
"type": "Stack",
"props": { "gap": "sm" },
"children": ["name-text", "email-text"]
},
"name-text": {
"type": "Text",
"props": { "content": "$data.user.name", "variant": "heading" },
"children": []
},
"email-text": {
"type": "Text",
"props": { "content": "$data.user.email", "variant": "caption" },
"children": []
},
"button-1": {
"type": "Button",
"props": { "label": "Edit Profile" },
"children": []
}
}
}
```
### Block-Level Spec
A high-level spec using semantic blocks for page layouts:
```json
{
"root": "page",
"elements": {
"page": {
"type": "Page",
"props": {},
"children": ["header", "hero", "features", "footer"]
},
"header": {
"type": "Header",
"props": { "logo": "/logo.svg", "navItems": ["Products", "Pricing", "Docs"] },
"children": []
},
"hero": {
"type": "Hero",
"props": {
"title": "Build UIs with JSON",
"subtitle": "Let AI generate your interfaces",
"ctaLabel": "Get Started",
"ctaHref": "/docs"
},
"children": []
},
"features": {
"type": "Features",
"props": { "columns": 3 },
"children": ["feature-1", "feature-2", "feature-3"]
},
"feature-1": {
"type": "Feature",
"props": { "icon": "zap", "title": "Fast", "description": "Render UIs in milliseconds" },
"children": []
},
"feature-2": {
"type": "Feature",
"props": { "icon": "shield", "title": "Secure", "description": "Validate all specs against your catalog" },
"children": []
},
"feature-3": {
"type": "Feature",
"props": { "icon": "sparkles", "title": "AI-Ready", "description": "Generate prompts from your catalog" },
"children": []
},
"footer": {
"type": "Footer",
"props": { "copyright": "2025 Acme Inc", "links": ["Privacy", "Terms", "Contact"] },
"children": []
}
}
}
```
## Spec Anatomy
### Root and Elements
Every spec has a `root` key pointing to the entry element, and an `elements` map containing all elements:
```json
{
"root": "card-1",
"elements": {
"card-1": {
"type": "Card",
"props": { "title": "My Card" },
"children": ["text-1"]
},
"text-1": { ... }
}
}
```
### Element Structure
Each element in the map has a consistent shape:
```json
{
"type": "ComponentName",
"props": { "label": "Hello" },
"children": ["child-1", "child-2"]
}
```
- `type` — Component type from your catalog
- `props` — Component properties
- `children` — Array of child element keys
### Dynamic Data
Props can reference data using `$data` paths:
```json
{
"type": "Metric",
"props": {
"label": "Total Revenue",
"value": "$data.metrics.revenue",
"change": "$data.metrics.revenueChange"
},
"children": []
}
```
### Conditional Visibility
Control when elements appear using the `visible` property:
```json
{
"type": "Alert",
"props": {
"message": "You have unsaved changes"
},
"children": [],
"visible": {
"path": "$data.form.isDirty",
"operator": "eq",
"value": true
}
}
```
## Working with Specs
### Rendering a Spec
```tsx
import { Renderer } from '@json-render/react';
function MyApp({ spec, data }) {
return (
);
}
```
### Validating a Spec
```typescript
import { validate } from '@json-render/core';
const result = validate(spec, catalog);
if (!result.valid) {
console.error('Invalid spec:', result.errors);
}
```
### Streaming Specs
Specs can be streamed incrementally for progressive rendering:
```tsx
import { useUIStream } from '@json-render/react';
function GenerativeUI() {
const { spec, isStreaming } = useUIStream({
api: '/api/generate',
});
return (
);
}
```
## Spec Sources
Specs can come from various sources:
- **AI Generation** — LLMs generate specs based on prompts and catalog
- **Database** — Store specs as JSON and load dynamically
- **API Response** — Server returns specs based on user/context
- **Static Files** — Pre-built specs for known UI patterns
## Next
Learn about [catalogs](/docs/catalog) — the vocabulary of components available in your specs.