PettyUI/.firecrawl/json-render.md
Mats Bosson db906fd85a Fix linting config and package fields
- Replace .eslintrc.cjs with eslint.config.mjs (ESLint 9 flat config)
  using direct eslint-plugin-solid + @typescript-eslint/parser approach
- Add @typescript-eslint/parser to root devDependencies
- Add main/module/types top-level fields to packages/core/package.json
- Add resolve.conditions to packages/core/vite.config.ts
- Create packages/core/tsconfig.test.json for test type-checking
- Remove empty paths:{} from packages/core/tsconfig.json
2026-03-29 02:35:57 +07:00

11 KiB

The Generative UI Framework

AI → json-render → UI

Generate dynamic, personalized UIs from prompts without sacrificing reliability. Predefined components and actions for safe, predictable output.

Create a contact form with name, email, and message

Create a login form with email and passwordBuild a feedback form with rating stars

jsonnestedstreamcatalog

{"op":"add","path":"/root","value":"card"}
{"op":"add","path":"/elements/name","value":{"type":"Input","props":{"label":"Name","name":"name","statePath":"/form/name","checks":[{"type":"required","message":"Name is required"}]}}}
{"op":"add","path":"/elements/email","value":{"type":"Input","props":{"label":"Email","name":"email","type":"email","statePath":"/form/email","checks":[{"type":"required","message":"Email is required"},{"type":"email","message":"Please enter a valid email"}]}}}
{
  "root": "card",
  "state": {
    "form": {
      "name": "",
      "email": "",
      "message": ""
    }
  },
  "elements": {
    "card": {
      "type": "Card",
      "props": {
        "title": "Contact Us",
        "maxWidth": "md"
      },
      "children": [\
        "name",\
        "email"\
      ]
    },
    "name": {
      "type": "Input",
      "props": {
        "label": "Name",
        "name": "name",
        "statePath": "/form/name",
        "checks": [\
          {\
            "type": "required",\
            "message": "Name is required"\
          }\
        ]
      }
    },
    "email": {
      "type": "Input",
      "props": {
        "label": "Email",
        "name": "email",
        "type": "email",
        "statePath": "/form/email",
        "checks": [\
          {\
            "type": "required",\
            "message": "Email is required"\
          },\
          {\
            "type": "email",\
            "message": "Please enter a valid email"\
          }\
        ]
      }
    }
  }
}
{
  "state": {
    "form": {
      "name": "",
      "email": "",
      "message": ""
    }
  },
  "elements": {
    "type": "Card",
    "props": {
      "title": "Contact Us",
      "maxWidth": "md"
    },
    "children": [\
      {\
        "type": "Input",\
        "props": {\
          "label": "Name",\
          "name": "name",\
          "statePath": "/form/name",\
          "checks": [\
            {\
              "type": "required",\
              "message": "Name is required"\
            }\
          ]\
        }\
      },\
      {\
        "type": "Input",\
        "props": {\
          "label": "Email",\
          "name": "email",\
          "type": "email",\
          "statePath": "/form/email",\
          "checks": [\
            {\
              "type": "required",\
              "message": "Email is required"\
            },\
            {\
              "type": "email",\
              "message": "Please enter a valid email"\
            }\
          ]\
        }\
      }\
    ]
  }
}

components (39)actions (6)

Accordion

Collapsible sections. Items as [{title, content}]. Type 'single' (default) or 'multiple'.

items: arraytype: enum?

Alert

Alert banner

title: stringmessage: string?type: enum?

Avatar

User avatar with fallback initials

src: string?name: stringsize: enum?

Badge

Status badge

text: stringvariant: enum?

BarGraph

Vertical bar chart

title: string?data: array

Button

Clickable button. Bind on.press for handler.

label: stringvariant: enum?disabled: boolean?

on.press

ButtonGroup

Segmented button group. Use { $bindState } on selected for selected value.

buttons: arrayselected: string?

on.change

Cardslots: default

Container card for content sections. Use for forms/content boxes, NOT for page headers.

title: string?description: string?maxWidth: enum?centered: boolean?

Carousel

Horizontally scrollable carousel of cards.

items: array

Checkbox

Checkbox input. Use { $bindState } on checked for binding.

label: stringname: stringchecked: boolean?

on.change

Collapsibleslots: default

Collapsible section with trigger. Children render inside.

title: stringdefaultOpen: boolean?

Dialogslots: default

Modal dialog. Set openPath to a boolean state path. Use setState to toggle.

title: stringdescription: string?openPath: string

Drawerslots: default

Bottom sheet drawer. Set openPath to a boolean state path. Use setState to toggle.

title: stringdescription: string?openPath: string

DropdownMenu

Dropdown menu with trigger button and selectable items.

label: stringitems: array

on.select

Gridslots: default

Grid layout (1-6 columns)

columns: number?gap: enum?

Heading

Heading text (h1-h4)

text: stringlevel: enum?

Image

Placeholder image (displays alt text in a styled box)

alt: stringwidth: number?height: number?

Input

Text input field. Use { $bindState } on value for two-way binding. Use checks for validation (e.g. required, email, minLength).

label: stringname: stringtype: enum?placeholder: string?value: string?checks: array?

on.submiton.focuson.blur

LineGraph

Line chart with points

title: string?data: array

Link

Anchor link. Bind on.press for click handler.

label: stringhref: string

on.press

Pagination

Page navigation. Use { $bindState } on page for current page number.

totalPages: numberpage: number?

on.change

Popover

Popover that appears on click of trigger.

trigger: stringcontent: string

Progress

Progress bar (value 0-100)

value: numbermax: number?label: string?

Radio

Radio button group. Use { $bindState } on value for binding.

label: stringname: stringoptions: arrayvalue: string?

on.change

Rating

Star rating display

value: numbermax: number?label: string?

Select

Dropdown select input. Use { $bindState } on value for binding. Use checks for validation.

label: stringname: stringoptions: arrayplaceholder: string?value: string?checks: array?

on.change

Separator

Visual separator line

orientation: enum?

Skeleton

Loading placeholder skeleton

width: string?height: string?rounded: boolean?

Slider

Range slider input. Use { $bindState } on value for binding.

label: string?min: number?max: number?step: number?value: number?

on.change

Spinner

Loading spinner indicator

size: enum?label: string?

Stackslots: default

Flex container for layouts

direction: enum?gap: enum?align: enum?justify: enum?

Switch

Toggle switch. Use { $bindState } on checked for binding.

label: stringname: stringchecked: boolean?

on.change

Table

Data table. columns: header labels. rows: 2D array of cell strings, e.g. "Alice","admin"],["Bob","user".

columns: arrayrows: arraycaption: string?

Tabs

Tab navigation. Use { $bindState } on value for active tab binding.

tabs: arraydefaultValue: string?value: string?

on.change

Text

Paragraph text

text: stringvariant: enum?

Textarea

Multi-line text input. Use { $bindState } on value for binding. Use checks for validation.

label: stringname: stringplaceholder: string?rows: number?value: string?checks: array?

Toggle

Toggle button. Use { $bindState } on pressed for state binding.

label: stringpressed: boolean?variant: enum?

on.change

ToggleGroup

Group of toggle buttons. Type 'single' (default) or 'multiple'. Use { $bindState } on value.

items: arraytype: enum?value: string?

on.change

Tooltip

Hover tooltip. Shows content on hover over text.

content: stringtext: string

live renderstatic code

export

Contact Us

Name

Email

npm install @json-render/core @json-render/react

Get Started GitHub

01

Define Your Catalog

Set the guardrails. Define which components, actions, and data bindings AI can use.

02

AI Generates

Describe what you want. AI generates JSON constrained to your catalog. Every interface is unique.

03

Render Instantly

Stream the response. Your components render progressively as JSON arrives.

Define your catalog

Components, actions, and validation functions.

import { defineSchema, defineCatalog } from '@json-render/core';
import { z } from 'zod';

const schema = defineSchema({ /* ... */ });

export const catalog = defineCatalog(schema, {
  components: {
    Card: {
      props: z.object({
        title: z.string(),
        description: z.string().nullable(),
      }),
      hasChildren: true,
    },
    Metric: {
      props: z.object({
        label: z.string(),
        statePath: z.string(),
        format: z.enum(['currency', 'percent']),
      }),
    },
  },
  actions: {
    export: { params: z.object({ format: z.string() }) },
  },
});

Show all

AI generates JSON

Constrained output that your components render natively.

{
  "root": "dashboard",
  "elements": {
    "dashboard": {
      "type": "Card",
      "props": {
        "title": "Revenue Dashboard"
      },
      "children": ["revenue"]
    },
    "revenue": {
      "type": "Metric",
      "props": {
        "label": "Total Revenue",
        "statePath": "/metrics/revenue",
        "format": "currency"
      }
    }
  }
}

Export as Code

Export generated UI as standalone React components. No runtime dependencies required.

Generated UI Tree

AI generates a JSON structure from the user's prompt.

{
  "root": "card",
  "elements": {
    "card": {
      "type": "Card",
      "props": { "title": "Revenue" },
      "children": ["metric", "chart"]
    },
    "metric": {
      "type": "Metric",
      "props": {
        "label": "Total Revenue",
        "statePath": "analytics/revenue",
        "format": "currency"
      }
    },
    "chart": {
      "type": "Chart",
      "props": {
        "statePath": "analytics/salesByRegion"
      }
    }
  }
}

Show all

Exported React Code

Export as a standalone Next.js project with all components.

"use client";

import { Card, Metric, Chart } from "@/components/ui";

const data = {
  analytics: {
    revenue: 125000,
    salesByRegion: [\
      { label: "US", value: 45000 },\
      { label: "EU", value: 35000 },\
    ],
  },
};

export default function Page() {
  return (
    <Card data={data} title="Revenue">
      <Metric
        data={data}
        label="Total Revenue"
        statePath="analytics/revenue"
        format="currency"
      />
      <Chart data={data} statePath="analytics/salesByRegion" />
    </Card>
  );
}

Show all

The export includespackage.json, component files, styles, and everything needed to run independently.

Features

Generative UI

Generate dynamic, personalized interfaces from prompts with AI

Guardrails

AI can only use components you define in the catalog

Streaming

Progressive rendering as JSON streams from the model

React & React Native

Render on web and mobile from the same catalog and spec format

Data Binding

Connect props to state with $state, $item, $index, and two-way binding

Code Export

Export as standalone React code with no runtime dependencies

Get started

npm install @json-render/core @json-render/react

Documentation

Ask AI ⌘I