2026-02-28 01:37:10 +00:00
# jsonsx
2026-02-28 01:10:49 +00:00
JSX factory for [json-render ](https://github.com/vercel-labs/json-render ). Write JSX, get Spec JSON.
## Install
```bash
2026-02-28 01:37:10 +00:00
bun add jsonsx @json -render/core
2026-02-28 01:10:49 +00:00
```
## Setup
2026-02-28 01:37:10 +00:00
Configure your `tsconfig.json` to use jsonsx as the JSX source:
2026-02-28 01:10:49 +00:00
```json
{
"compilerOptions": {
"jsx": "react-jsx",
2026-02-28 01:37:10 +00:00
"jsxImportSource": "jsonsx"
2026-02-28 01:10:49 +00:00
}
}
```
Or use a per-file pragma:
```tsx
2026-02-28 01:37:10 +00:00
/** @jsxImportSource jsonsx */
2026-02-28 01:10:49 +00:00
```
## Usage
### Define components
Create wrapper functions that map JSX tags to json-render component type names:
```ts
2026-02-28 01:37:10 +00:00
import { jsx } from "jsonsx/jsx-runtime";
import type { JsonsxNode } from "jsonsx";
2026-02-28 01:10:49 +00:00
2026-02-28 01:37:10 +00:00
export function Stack(props: Record< string , unknown > ): JsonsxNode {
2026-02-28 01:10:49 +00:00
return jsx("Stack", props);
}
2026-02-28 01:37:10 +00:00
export function Text(props: Record< string , unknown > ): JsonsxNode {
2026-02-28 01:10:49 +00:00
return jsx("Text", props);
}
2026-02-28 01:37:10 +00:00
export function Button(props: Record< string , unknown > ): JsonsxNode {
2026-02-28 01:10:49 +00:00
return jsx("Button", props);
}
```
### Render JSX to Spec JSON
```tsx
2026-02-28 01:37:10 +00:00
import { render } from "jsonsx";
2026-02-28 01:10:49 +00:00
import { Stack, Text, Button } from "./components";
const spec = render(
< Stack >
2026-02-28 01:37:10 +00:00
< Text content = "Hello from jsonsx!" / >
2026-02-28 01:10:49 +00:00
< Button label = "Click me" / >
< / Stack >
);
```
This produces:
```json
{
"root": "stack-1",
"elements": {
"text-1": {
"type": "Text",
2026-02-28 01:37:10 +00:00
"props": { "content": "Hello from jsonsx!" }
2026-02-28 01:10:49 +00:00
},
"button-1": {
"type": "Button",
"props": { "label": "Click me" }
},
"stack-1": {
"type": "Stack",
"props": {},
"children": ["text-1", "button-1"]
}
}
}
```
### State, events, visibility, and watchers
Pass json-render bindings as JSX props:
```tsx
const spec = render(
< Stack >
< Text content = {{ $ state: " / count " } } / >
< Button
label="Increment"
on={{
press: {
action: "increment",
params: { statePath: "/count" },
},
}}
/>
< Text
content="Hidden until toggled"
visible={{ $state: "/showDetails", eq: true }}
/>
< / Stack > ,
{
state: {
count: 0,
showDetails: false,
},
}
);
```
The `render()` function accepts an options object with `state` to include initial state in the Spec output.
### Reserved props
These props are extracted from JSX and mapped to Spec fields rather than passed through as component props:
| Prop | Spec field | Description |
|---|---|---|
| `key` | element key | Explicit element key (overrides auto-generation) |
| `visible` | `visible` | Visibility condition |
| `on` | `on` | Event bindings |
| `repeat` | `repeat` | Repeat configuration |
| `watch` | `watch` | State watchers |
| `children` | `children` | Child element references |
## Example
2026-02-28 01:37:10 +00:00
The `example/` directory contains a Bun HTTP server that demonstrates jsonsx in action. It shows JSX source, live rendered UI (via `@json-render/react` ), and JSON output side by side.
2026-02-28 01:10:49 +00:00
```bash
cd example
bun install
bun dev
```
This starts a dev server with HMR at `http://localhost:3000` .
## Development
```bash
bun install # install dependencies
bun run build # build dist/
bun test # run tests
bun run typecheck # type check
```
## License
MIT