import { pageMetadata } from "@/lib/page-metadata"
export const metadata = pageMetadata("docs/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 uses components from a [catalog](/docs/catalog) and can optionally follow a [schema](/docs/schemas). 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": { "$state": "/user/greeting" } },
      "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": { "$state": "/user/avatar" }, "alt": { "$state": "/user/name" } },
      "children": []
    },
    "stack-1": {
      "type": "Stack",
      "props": { "gap": "sm" },
      "children": ["name-text", "email-text"]
    },
    "name-text": {
      "type": "Text",
      "props": { "content": { "$state": "/user/name" }, "variant": "heading" },
      "children": []
    },
    "email-text": {
      "type": "Text",
      "props": { "content": { "$state": "/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

Specs are schema-agnostic — the JSON structure is entirely up to you. The examples below use the `root` + `elements` flat tree format from the `@json-render/react` schema, which is optimized for AI generation and streaming.

### Root and Elements

In the React schema, a 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 from the state model using `$state` expressions. The value is a JSON Pointer (RFC 6901) path into the state:

```json
{
  "type": "Metric",
  "props": {
    "label": "Total Revenue",
    "value": { "$state": "/metrics/revenue" },
    "change": { "$state": "/metrics/revenueChange" }
  },
  "children": []
}
```

See [Data Binding](/docs/data-binding) for the full reference including `$item`, `$index`, repeat, and two-way binding.

### Conditional Visibility

Control when elements appear using the `visible` property:

```json
{
  "type": "Alert",
  "props": {
    "message": "You have unsaved changes"
  },
  "children": [],
  "visible": {
    "$state": "/form/isDirty",
    "eq": true
  }
}
```

## Working with Specs

### Validating a Spec

Use `validateSpec` from `@json-render/core` to check a spec for structural issues:

```typescript
import { validateSpec } from '@json-render/core';

const result = validateSpec(spec);

if (!result.valid) {
  console.error('Invalid spec:', result.issues);
}
```

### Rendering a Spec (React)

With `@json-render/react`, wrap the `Renderer` in providers to supply state and visibility:

```tsx
import { Renderer, StateProvider, VisibilityProvider } from '@json-render/react';
import { registry } from './registry';

function MyApp({ spec, initialState }) {
  return (
    <StateProvider initialState={initialState}>
      <VisibilityProvider>
        <Renderer spec={spec} registry={registry} />
      </VisibilityProvider>
    </StateProvider>
  );
}
```

See the [@json-render/react API reference](/docs/api/react) for full provider and hook documentation.

### Streaming a Spec (React)

With `@json-render/react`, use the `useUIStream` hook to stream specs incrementally:

```tsx
import { useUIStream } from '@json-render/react';

function GenerativeUI() {
  const { spec, isStreaming } = useUIStream({
    api: '/api/generate',
  });

  return (
    <Renderer
      spec={spec}
      registry={registry}
      loading={isStreaming}
    />
  );
}
```

See [Streaming](/docs/streaming) for the full SpecStream format and server-side setup.

## 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.
