⚠️ Alpha · testnets only. ChainRender is in active alpha and deployed on testnets only — Ethereum Sepolia, the Robinhood Chain Testnet, and the Circle Arc Testnet — not on any mainnet. Contracts, addresses, and APIs may change. Do not use with real funds or production assets.
Guides

Guide: Using ChainRender with React

@chainrender/client/react provides a component and a hook for rendering on-chain apps in React. React is an optional peer dependency — install it alongside the SDK:

npm install @chainrender/client react react-dom

The <ChainRenderView> component

Drop-in rendering of a deployed app, with loading and fail-closed states handled:

import { ChainRenderView } from "@chainrender/client/react";

const deployment = { rpc: "https://…", router: "0xRenderRouter" };

export function App() {
  return <ChainRenderView deployment={deployment} hash="0xAppHash" />;
}

Props: deployment ({ rpc, router }), hash, and optional resolvers, styleSheet, className.

The useChainRenderComponent hook

For custom rendering, the hook gives you the resolved HTML plus loading/error state:

import { useChainRenderComponent } from "@chainrender/client/react";

function MyView() {
  const { html, loading, error } = useChainRenderComponent(deployment, "0xAppHash");
  if (loading) return <Spinner />;
  if (error) return <Fallback error={error} />;
  return <div dangerouslySetInnerHTML={{ __html: html! }} />;
}

The HTML comes from the chain (a free eth_call) and is safe by construction — the interpreter escapes all resolver output, so there's no injection risk in the __html.

Authoring in React

Compose and grade with the core SDK (framework-agnostic), then render with the React layer:

import { compose, compileComponent, grade } from "@chainrender/client";

const app = compose.box([ compose.heading("Hi"), compose.text("On-chain.") ]);
const built = compileComponent(app);
const g = grade(app);   // show a live grade badge in your UI

Related

React is the shell, not the renderer

Use React for chrome — routing, wallet connection, layout — but let ChainRender render the actual UI: call renderComponent, get on-chain HTML, display it. React should not re-implement what the component renders, and you should not fetch on-chain data with viem and hand-render it (that bypasses ChainRender entirely). See Building Correctly.