Loading...
Loading...
Drop-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`.
npx skill4agent add vercel-labs/json-render devtoolsnullNODE_ENV === "production"# React
npm install @json-render/devtools @json-render/devtools-react
# Vue
npm install @json-render/devtools @json-render/devtools-vue
# Svelte
npm install @json-render/devtools @json-render/devtools-svelte
# Solid
npm install @json-render/devtools @json-render/devtools-solid<JsonRenderDevtools /><JSONUIProvider>import { JsonRenderDevtools } from "@json-render/devtools-react";
<JSONUIProvider registry={registry} handlers={handlers}>
<Renderer spec={spec} registry={registry} />
<JsonRenderDevtools spec={spec} catalog={catalog} messages={messages} />
</JSONUIProvider>;<script setup>
import { JsonRenderDevtools } from "@json-render/devtools-vue";
</script>
<template>
<JSONUIProvider :registry="registry">
<Renderer :spec="spec" :registry="registry" />
<JsonRenderDevtools :spec="spec" :catalog="catalog" :messages="messages" />
</JSONUIProvider>
</template><script>
import { JsonRenderDevtools } from "@json-render/devtools-svelte";
</script>
<JSONUIProvider {registry}>
<Renderer {spec} {registry} />
<JsonRenderDevtools {spec} {catalog} {messages} />
</JSONUIProvider>import { JsonRenderDevtools } from "@json-render/devtools-solid";
<JSONUIProvider registry={registry}>
<Renderer spec={spec()} registry={registry} />
<JsonRenderDevtools
spec={spec()}
catalog={catalog}
messages={messages()}
/>
</JSONUIProvider>;CtrlCmdShiftJhotkeyspecSpec | nullcatalogCatalog | nullmessagesUIMessage[]useChatinitialOpenbooleanposition"bottom-right" | "bottom-left" | "right""bottom-*""right"100vhhotkeystring | false"mod+shift+j"bufferSizenumberreserveSpacebooleantruepadding-bottompadding-rightbodyfalseallowDockTogglebooleantruelocalStoragepositionfalsepositiononEvent(DevtoolsEvent) => voidspec.rootvalidateSpecstore.setEsclocalStorageallowDockToggle={false}positionheight: 100%html { height: 100% }body { height: 100% }.app { height: 100% }--jr-devtools-offset-bottompadding-bottombodyposition="right"100vhposition: fixed; bottom: 0--jr-devtools-offset-right100vhposition: fixedposition: sticky.composer { bottom: var(--jr-devtools-offset-bottom, 0); }
.sidebar { right: var(--jr-devtools-offset-right, 0); }
.app-shell { height: calc(100vh - var(--jr-devtools-offset-bottom, 0)); }reserveSpace={false}--jr-devtools-offset<JsonRenderDevtools /><Renderer /><JSONUIProvider><Renderer spec={msgSpec} registry={registry} />StateProvidermessageId<id>-root/<id>/countspec={latest}messages={all}specmessagesregisterActionObserverActionProviderdata-jr-keyexamples/devtoolsimport { useJsonRenderDevtools } from "@json-render/devtools-react";
const devtools = useJsonRenderDevtools();
devtools?.open();
devtools?.toggle();
devtools?.recordEvent({ kind: "stream-text", at: Date.now(), text: "hi" });nullimport { tapJsonRenderStream, createEventStore } from "@json-render/devtools";
import { pipeJsonRender } from "@json-render/core";
const events = createEventStore({ bufferSize: 1000 });
const tapped = tapJsonRenderStream(result.toUIMessageStream(), events);
writer.merge(pipeJsonRender(tapped));tapYamlStreamActionProvidernotifyActionDispatchnotifyActionSettle@json-render/coreregisterActionObserverElementRenderer<span data-jr-key="..." style="display:contents">