solid — скилл для Claude Code: рендер SolidJS UI из JSON
Скилл для рендеринга JSON-spec в реактивные SolidJS компоненты. Пригодится, если собираешь каталоги UI, настраиваешь провайдеры или разбираешься с реактивностью Solid.
npx skills add vercel-labs/json-render --skill solid -a claude-codeЧто делает solid
@json-render/solid превращает JSON-описания в живые Solid компоненты с fine-grained реактивностью. Оборачиваешь приложение в JSONUIProvider, передаёшь спек и реестр — скилл обрабатывает биндинги состояния, видимость элементов, валидацию и экшены.
Внутри четыре провайдера: StateProvider для синхронизации состояния, VisibilityProvider для условной видимости, ValidationProvider для проверки форм, ActionProvider для встроенных и кастомных действий. Компоненты получают emit для событий и useBoundProp для двусторонних биндингов. Поддерживает шаблоны, вычисляемые значения, условия и повторы через repeat.statePath.
Скилл требует знания правил реактивности Solid: не деструктури пропсы в сигнатуре функции, если они меняются, читай реактивные значения внутри JSX или createMemo. Если нужна потоковая генерация UI, используй useUIStream или useChatUI.
Какие задачи решает
- рендерить UI из JSON-спеков в SolidJS приложение
- связать состояние компонентов с JSON-биндингами
- валидировать форму и синхронизировать состояние
- обработать события компонентов и запустить кастомные экшены
- генерировать UI потоком от API
Примеры запросов агенту
- Собери каталог с `defineCatalog`, зарегистрируй компоненты в `defineRegistry`, обёрнутый в `JSONUIProvider`
- Напиши компонент, используй `useBoundProp` для двусторонней привязки значения к состоянию
- Настрой `useUIStream` и отправь промпт, чтобы API генерировал UI спек, а `Renderer` его отображал
Как установить solid
1Через Skills CLI (Vercel)
npx skills add vercel-labs/json-render --skill solid -a claude-code2Вручную: положить файлы
~/.claude/skills/solid/SKILL.mdПапка скилла целиком; для одного проекта — .claude/skills/solid/
1Через Skills CLI (Vercel)
npx skills add vercel-labs/json-render --skill solid -a codex2Вручную: положить файлы
.agents/skills/solid/SKILL.mdДля всех проектов — ~/.agents/skills/
1Через Skills CLI (Vercel)
npx skills add vercel-labs/json-render --skill solid -a cursor2Вручную: положить файлы
.cursor/skills/solid/SKILL.mdCursor читает и .agents/skills/, и .claude/skills/
1GitHub CLI
gh skill install vercel-labs/json-render solid2Вручную: положить файлы
.github/skills/solid/SKILL.md1Через Skills CLI (Vercel)
npx skills add vercel-labs/json-render --skill solid -a gemini-cli2Командой платформы
gemini skills install https://github.com/vercel-labs/json-render --path skills/solidВручную: положить файлы
.devin/skills/solid/SKILL.mdСтарый путь .windsurf/skills/ тоже читается
Через Skills CLI (Vercel)
npx skills add vercel-labs/json-render --skill solid -a opencodeClaude.ai
Упакуйте папку в zip и загрузите в Settings → Capabilities → Skills
Из того же набора20
Весь набор →Похожие
Вопросы о solid
Как установить solid в Claude Code?
Запусти npx skills add vercel-labs/json-render --skill solid -a claude-code, потом проверь файл ~/.claude/skills/solid/SKILL.md.
Что делает solid?
Скилл рендерит JSON-описания UI в реактивные SolidJS компоненты, автоматически синхронизируя состояние, видимость, валидацию и обработку событий.
Как сделать двусторонний биндинг значения в форме?
Используй useBoundProp(props.props.value, props.bindings?.value) — она вернёт текущее значение и функцию для записи в состояние. Читай значение внутри JSX, чтобы оно оставалось реактивным.
Исходный текст
SKILL.md · Apache-2.0
---
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
Nested lists can set `repeat.statePath` to `{ "$item": "field" }` inside an enclosing repeat.
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, type BaseComponentProps } from "@json-render/solid";
function Input(props: BaseComponentProps<{ value?: string }>) {
const [, setValue] = useBoundProp(props.props.value, props.bindings?.value);
return (
<input
value={String(props.props.value ?? "")}
onInput={(e) => setValue(e.currentTarget.value)}
/>
);
}
```
`useBoundProp` returns a scalar value and a write-back setter. Read the resolved prop inside JSX so later state updates remain reactive.
`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.
© vercel-labs · Apache-2.0 · vercel-labs/json-render