
Svelte JSON Renderer
OfficialFreeTransform JSON specs into Svelte components effortlessly.
Free · Opens the source repo
What Svelte JSON Renderer does
The Svelte JSON Renderer is a specialized tool designed for developers working with Svelte applications. It allows you to convert JSON specifications into Svelte component trees, making it easier to build UIs dynamically from structured data. This renderer is particularly useful when integrating with the @json-render/svelte library, as it simplifies the process of rendering complex component structures defined in JSON format.
By utilizing the Svelte JSON Renderer, you can create component catalogs and manage dynamic components with ease. The renderer supports defining components with specific props and behaviors, allowing for a structured approach to component development. You can register components and their actions, making it straightforward to handle events and manage state across your application.
This skill is aimed at developers who are looking to streamline their workflow when working with Svelte and JSON data. It provides a clear framework for defining components, their properties, and how they interact with user input and application state. Whether you're building a component library or rendering AI-generated specifications, this tool enhances your capability to create responsive and dynamic UIs.
In addition to component rendering, the Svelte JSON Renderer offers features like visibility conditions and dynamic props, allowing for conditional rendering based on application state. This flexibility is essential for creating interactive applications that respond to user actions and data changes effectively.
When to use it
Use this skill when you need to render Svelte components from JSON data, especially in dynamic UI scenarios.
When not to use it
This skill may not be suitable for static applications where JSON rendering is unnecessary or for projects not utilizing Svelte.
What you can build with it
Dynamic UI Rendering
Render Svelte components dynamically from JSON data, allowing for flexible and responsive UIs.
Component Catalog Management
Create and manage a catalog of reusable Svelte components defined by JSON specifications.
AI-Generated Spec Rendering
Use the renderer to display AI-generated specifications as interactive Svelte components.
How to install Svelte JSON Renderer
View source1. Install with the skills CLI
npx skills add vercel-labs/json-render/svelte --agent claude-code2. Or install it manually
Download the skill folder and drop it into ~/.claude/skills/ for all projects, or .claude/skills/ to scope it to one repo. Restart Claude Code so it picks up the new skill.
Anthropic's agentic coding CLI, and the reference implementation of Agent Skills. Drop a skill folder into ~/.claude/skills and Claude Code loads it automatically whenever a task matches the skill's description. Claude Code docs
Inside SKILL.md
Written by vercel-labs@json-render/svelte
Svelte 5 renderer that converts json-render specs into Svelte component trees.
Quick Start
<script lang="ts">
import { Renderer, JsonUIProvider } from "@json-render/svelte";
import type { Spec } from "@json-render/svelte";
import Card from "./components/Card.svelte";
import Button from "./components/Button.svelte";
interface Props {
spec: Spec | null;
}
let { spec }: Props = $props();
const registry = { Card, Button };
</script>
<JsonUIProvider>
<Renderer {spec} {registry} />
</JsonUIProvider>
Creating a Catalog
import { defineCatalog } from "@json-render/core";
import { schema } from "@json-render/svelte";
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 with title",
},
},
});
Defining Components
Components should accept BaseComponentProps<TProps>:
interface BaseComponentProps<TProps> {
props: TProps; // Resolved props for this component
children?: Snippet; // Child elements (use {@render children()})
emit: (event: string) => void; // Fire a named event
bindings?: Record<string, string>; // Map of prop names to state paths (for $bindState)
loading?: boolean; // True while spec is streaming
}
<!-- Button.svelte -->
<script lang="ts">
import type { BaseComponentProps } from "@json-render/svelte";
interface Props extends BaseComponentProps<{ label: string; variant?: string }> {}
let { props, emit }: Props = $props();
</script>
<button class={props.variant} onclick={() => emit("press")}>
{props.label}
</button>
<!-- Card.svelte -->
<script lang="ts">
import type { Snippet } from "svelte";
import type { BaseComponentProps } from "@json-render/svelte";
interface Props extends BaseComponentProps<{ title: string }> {
children?: Snippet;
}
let { props, children }: Props = $props();
</script>
<div class="card">
<h2>{props.title}</h2>
{#if children}
{@render children()}
{/if}
</div>
Creating a Registry
import { defineRegistry } from "@json-render/svelte";
import { catalog } from "./catalog";
import Card from "./components/Card.svelte";
import Button from "./components/Button.svelte";
const { registry, handlers, executeAction } = defineRegistry(catalog, {
components: {
Card,
Button,
},
actions: {
submit: async (params, setState, state) => {
// handle action
},
},
});
Spec Structure (Element Tree)
The Svelte schema uses the element tree format:
{
"root": "card1",
"elements": {
"card1": {
"type": "Card",
"props": { "title": "Hello" },
"children": ["btn1"]
},
"btn1": {
"type": "Button",
"props": { "label": "Click me" }
}
}
}
Visibility Conditions
Use visible on elements to show/hide based on state:
{ "$state": "/path" }- truthy check{ "$state": "/path", "eq": value }- equality check{ "$state": "/path", "not": true }- falsy check{ "$and": [cond1, cond2] }- AND conditions{ "$or": [cond1, cond2] }- OR conditions
Providers (via JsonUIProvider)
JsonUIProvider composes all contexts. Individual contexts:
| Context | Purpose |
|---|---|
StateContext | Share state across components (JSON Pointer paths) |
ActionContext | Handle actions dispatched via the event system |
VisibilityContext | Enable conditional rendering based on state |
ValidationContext | Form field validation |
Event System
Components use emit to fire named events. The element's on field maps events to action bindings:
<!-- Button.svelte -->
<script lang="ts">
import type { BaseComponentProps } from "@json-render/svelte";
interface Props extends BaseComponentProps<{ label: string }> {}
let { props, emit }: Props = $props();
</script>
<button onclick={() => emit("press")}>{props.label}</button>
{
"type": "Button",
"props": { "label": "Submit" },
"on": { "press": { "action": "submit" } }
}
Built-in Actions
The setState action is handled automatically and updates the state model:
{
"action": "setState",
"actionParams": { "statePath": "/activeTab", "value": "home" }
}
Other built-in actions: pushState, removeState, push, pop.
Dynamic Props and Two-Way Binding
Expression forms resolved before your component receives props:
{"$state": "/state/key"}- read from state{"$bindState": "/form/email"}- read + write-back to state{"$bindItem": "field"}- read + write-back for repeat items{"$cond": <condition>, "$then": <value>, "$else": <value>}- conditional value
For writable bindings inside components, use getBoundProp:
<script lang="ts">
import { getBoundProp } from "@json-render/svelte";
import type { BaseComponentProps } from "@json-render/svelte";
interface Props extends BaseComponentProps<{ value?: string }> {}
let { props, bindings }: Props = $props();
let value = getBoundProp<string>(
() => props.value,
() => bindings?.value,
);
</script>
<input bind:value={value.current} />
Context Helpers
Preferred helpers:
getStateValue(path)- returns{ current }(read/write)getBoundProp(() => value, () => bindingPath)- returns{ current }(read/write when bound)isVisible(condition)- returns{ current }(boolean)getAction(name)- returns{ current }(registered handler)
Advanced context access:
getStateContext()getActionContext()getVisibilityContext()getValidationContext()getOptionalValidationContext()getFieldValidation(ctx, path, config?)
Streaming UI
Use createUIStream for spec streaming:
<script lang="ts">
import { createUIStream, Renderer } from "@json-render/svelte";
const stream = createUIStream({
api: "/api/generate-ui",
onComplete: (spec) => console.log("Done", spec),
});
async function generate() {
await stream.send("Create a login form");
}
</script>
<button onclick={generate} disabled={stream.isStreaming}>
{stream.isStreaming ? "Generating..." : "Generate UI"}
</button>
{#if stream.spec}
<Renderer spec={stream.spec} {registry} loading={stream.isStreaming} />
{/if}
Use createChatUI for chat + UI responses:
const chat = createChatUI({ api: "/api/chat-ui" });
await chat.send("Build a settings panel");
Frequently asked questions about Svelte JSON Renderer
Similar skills
Playwright Component Testing
Test React and Vue components in isolation with Playwright.
Fluent UI Blazor
Integrate Fluent UI components in Blazor applications effortlessly.
Build MCP App
Create interactive UI widgets for MCP servers.
Web Design Reviewer
Identify and fix design issues in websites efficiently.
Markstream Install
Seamlessly integrate Markstream for Markdown rendering.
GSAP & Framer Scroll Animation
Create advanced scroll animations effortlessly.
