A React renderer for Dear ImGui that compiles to WebAssembly using Emscripten.
Write ImGui UIs using React components with JSX syntax.
- React 19 with custom reconciler for ImGui
- JSX Components for windows, text, buttons, tables, and more
- Custom Drawing with shapes (rect, circle, line) on the background canvas
- Watch Mode for fast development iteration
- Modular WASM with explicit initialization
- macOS/Linux: CMake, SDL2, Emscripten, Bun
- Install dependencies via Homebrew:
brew install cmake sdl2 emscripten bun
./build-wasm-dev.sh
cd dist && python3 -m http.server 8000
# Open http://localhost:8000./build-wasm-dev.sh --watch
# Rebuilds automatically when src/ files change./build-wasm-prod.sh
cd dist && python3 -m http.server 8000import React, { useState } from "react";
import { createRoot, renderRoot } from "./react-imgui-reconciler";
function App() {
const [count, setCount] = useState(0);
return (
<root>
{/* Background shapes */}
<rect x={10} y={10} width={100} height={50} color="#3030A0" filled />
{/* ImGui window */}
<window title="Hello React!" defaultX={100} defaultY={100}>
<text color="#00FFFF">Welcome to React + ImGui!</text>
<separator />
<button onClick={() => setCount(count + 1)}>
Clicked {count} times
</button>
</window>
</root>
);
}
const root = createRoot();
renderRoot(<App />, root);<root>- Root component (required, renders to fullscreen canvas)<window>- ImGui window with title, position, size props<child>- Scrollable child region<group>- Group elements together<indent>/<unindent>- Indentation<sameline>- Put next element on same line<separator>- Horizontal separator<dummy>- Invisible spacer
<text>- Text with optionalcolorandwrappedprops<textdisabled>- Grayed out text
<button>- Clickable button withonClick<collapsingheader>- Collapsible section
<table>- Table container withcolumnsprop<tablecolumn>- Column definition<tableheader>- Header row<tablerow>- Table row<tablecell>- Table cell withindexprop
<rect>- Rectangle withx,y,width,height,color,filled<circle>- Circle withx,y,radius,color,filled,segments<line>- Line withx1,y1,x2,y2,color,thickness
// Uncontrolled (initial position/size)
<window
title="My Window"
defaultX={100}
defaultY={100}
defaultWidth={400}
defaultHeight={300}
/>
// Controlled (React manages position/size)
<window
title="Controlled Window"
x={windowState.x}
y={windowState.y}
width={windowState.width}
height={windowState.height}
onWindowState={(x, y, width, height) => setWindowState({ x, y, width, height })}
/>.
├── src/
│ ├── main.cpp # C++ ImGui bindings (EMSCRIPTEN_KEEPALIVE exports)
│ ├── app.jsx # React application entry point
│ ├── react-imgui-reconciler.js # Custom React reconciler for ImGui
│ └── index.html # HTML template with cwrap bindings
├── external/
│ └── imgui/ # Dear ImGui library
├── dist/ # Build output (index.html, bundle.js)
├── build.js # esbuild configuration
├── CMakeLists.txt # CMake/Emscripten configuration
├── build-wasm-dev.sh # Development build script
└── build-wasm-prod.sh # Production build script
- Optimization:
-O0(fast compilation) - Watch Mode:
--watchflag for auto-rebuild - Output:
dist/directory
- Optimization:
-O3with Closure compiler - Output:
dist/directory
- React 19 with custom reconciler (
react-reconciler) - Dear ImGui for immediate-mode UI
- Emscripten compiles C++ to WebAssembly
- SDL2 + WebGL for rendering
- esbuild bundles JavaScript/JSX
The reconciler translates React's declarative component tree into ImGui's immediate-mode API calls every frame via the buildUI() callback.
MIT. Dear ImGui is also MIT licensed - see external/imgui/LICENSE.txt.