solid
$
npx mdskill add vercel-labs/json-render/solidRender JSON specifications into interactive SolidJS components for building dynamic UIs.
- Build structured, reactive user interfaces from declarative JSON schemas.
- Integrates with SolidJS and the core json-render library for rendering.
- Determines component structure and behavior based on provided schema definitions.
- Outputs a fully functional, reactive component tree within a SolidJS environment.
SKILL.md
.github/skills/solidView on GitHub ↗
---
name: solid
description: SolidJS renderer for json-render. Use when building @json-render/solid catalogs/registries, wiring Renderer providers, implementing bindings/actions, or troubleshooting Solid-specific reactivity patterns.
---
# @json-render/solid
`@json-render/solid` renders json-render specs into Solid component trees with fine-grained reactivity.
## Quick Start
```tsx
import { Renderer, JSONUIProvider } from "@json-render/solid";
import type { Spec } from "@json-render/solid";
import { registry } from "./registry";
export function App(props: { spec: Spec | null }) {
return (
<JSONUIProvider registry={registry} initialState={{}}>
<Renderer spec={props.spec} registry={registry} />
</JSONUIProvider>
);
}
```
## Create a Catalog
```typescript
import { defineCatalog } from "@json-render/core";
import { schema } from "@json-render/solid/schema";
import { z } from "zod";
export const catalog = defineCatalog(schema, {
components: {
Button: {
props: z.object({
label: z.string(),
variant: z.enum(["primary", "secondary"]).nullable(),
}),
description: "Clickable button",
},
Card: {
props: z.object({ title: z.string() }),
description: "Card container",
},
},
actions: {
submit: { description: "Submit data" },
},
});
```
## Define Components
Components receive `ComponentRenderProps` from the renderer:
```ts
interface ComponentRenderProps<P = Record<string, unknown>> {
element: UIElement<string, P>;
children?: JSX.Element;
emit: (event: string) => void;
on: (event: string) => EventHandle;
bindings?: Record<string, string>;
loading?: boolean;
}
```
Example:
```tsx
import type { BaseComponentProps } from "@json-render/solid";
export function Button(props: BaseComponentProps<{ label: string }>) {
return (
<button onClick={() => props.emit("press")}>{props.props.label}</button>
);
}
```
## Create a Registry
```typescript
import { defineRegistry } from "@json-render/solid";
import { catalog } from "./catalog";
import { Card } from "./Card";
import { Button } from "./Button";
const { registry, handlers, executeAction } = defineRegistry(catalog, {
components: {
Card,
Button,
},
actions: {
submit: async (params, setState, state) => {
// custom action logic
},
},
});
```
## Spec Structure
```json
{
"root": "card1",
"elements": {
"card1": {
"type": "Card",
"props": { "title": "Hello" },
"children": ["btn1"]
},
"btn1": {
"type": "Button",
"props": { "label": "Click me" },
"on": {
"press": { "action": "submit" }
}
}
}
}
```
## Providers
- `StateProvider`: state model read/write and controlled mode via `store`
- `VisibilityProvider`: evaluates `visible` conditions
- `ValidationProvider`: field validation + `validateForm` integration
- `ActionProvider`: runs built-in and custom actions
- `JSONUIProvider`: combined provider wrapper
## Hooks
- `useStateStore`, `useStateValue`, `useStateBinding`
- `useVisibility`, `useIsVisible`
- `useActions`, `useAction`
- `useValidation`, `useOptionalValidation`, `useFieldValidation`
- `useBoundProp`
- `useUIStream`, `useChatUI`
## Built-in Actions
Handled automatically by `ActionProvider`:
- `setState`
- `pushState`
- `removeState`
- `validateForm`
## Dynamic Props and Bindings
Supported expression forms include:
- `{"$state": "/path"}`
- `{"$bindState": "/path"}`
- `{"$bindItem": "field"}`
- `{"$template": "Hi ${/user/name}"}`
- `{"$computed": "fn", "args": {...}}`
- `{"$cond": <condition>, "$then": <value>, "$else": <value>}`
Use `useBoundProp` in components for writable bound values:
```tsx
import { useBoundProp } from "@json-render/solid";
function Input(props: BaseComponentProps<{ value?: string }>) {
const [value, setValue] = useBoundProp(
props.props.value,
props.bindings?.value,
);
return (
<input
value={String(value() ?? "")}
onInput={(e) => setValue(e.currentTarget.value)}
/>
);
}
```
`useStateValue`, `useStateBinding`, and the `state` / `errors` / `isValid` fields from `useFieldValidation` are reactive accessors in Solid. Call them as functions inside JSX, `createMemo`, or `createEffect`.
## Solid Reactivity Rules
- Do not destructure component props in function signatures when values need to stay reactive.
- Keep changing reads inside JSX expressions, `createMemo`, or `createEffect`.
- Context values are exposed through getter-based objects so consumers always observe live signals.
## Streaming UI
```tsx
import { useUIStream, Renderer } from "@json-render/solid";
const stream = useUIStream({ api: "/api/generate-ui" });
await stream.send("Create a support dashboard");
<Renderer
spec={stream.spec}
registry={registry}
loading={stream.isStreaming}
/>;
```
Use `useChatUI` for chat + UI generation flows.
More from vercel-labs/json-render
- codegenCode generation utilities for json-render. Use when generating code from UI specs, building custom code exporters, traversing specs, or serializing props for @json-render/codegen.
- devtoolsDrop-in inspector panel for any json-render app. Use when the user wants to debug a generative UI, inspect the spec tree, edit state at runtime, see dispatched actions, follow stream patches live, browse a catalog, or pick DOM elements to find their spec keys. Triggers include "add devtools", "debug json-render", "inspect the spec", "why is this element not rendering", "see the state at runtime", or requests to tap streams / capture action logs for `@json-render/devtools`.
- directivesPre-built custom directives for json-render — formatting, math, string manipulation, and i18n. Use when working with @json-render/directives, defining custom directives with defineDirective, or adding $format, $math, $concat, $count, $truncate, $pluralize, $join, or $t to specs.
- imageImage renderer for json-render that turns JSON specs into SVG and PNG images via Satori. Use when working with @json-render/image, generating OG images from JSON, creating social cards, or rendering AI-generated image specs.
- inkInk terminal renderer for json-render that turns JSON specs into interactive terminal UIs. Use when working with @json-render/ink, building terminal UIs from JSON, creating terminal component catalogs, or rendering AI-generated specs in the terminal.
- jotaiJotai adapter for json-render's StateStore interface. Use when integrating json-render with Jotai for state management via @json-render/jotai.
- mcpMCP Apps integration for json-render. Use when building MCP servers that render interactive UIs in Claude, ChatGPT, Cursor, or VS Code, or when integrating json-render with the Model Context Protocol.
- nextNext.js renderer for json-render that turns JSON specs into full Next.js applications with routes, layouts, SSR, and metadata. Use when working with @json-render/next, building Next.js apps from JSON specs, or creating AI-generated multi-page applications.
- reactReact renderer for json-render that turns JSON specs into React components. Use when working with @json-render/react, building React UIs from JSON, creating component catalogs, or rendering AI-generated specs.
- react-emailReact Email renderer for json-render that turns JSON specs into HTML or plain-text emails using @react-email/components and @react-email/render. Use when working with @json-render/react-email, building transactional or marketing emails from JSON, creating email catalogs, rendering AI-generated email specs, or when the user mentions react-email, HTML email, or transactional email.