5.6 KiB
React Configuration
Project Setup
Quick Start
bunx create-tui@latest -t react my-app
cd my-app && bun install
The CLI creates the my-app directory for you - it must not already exist.
Options: --no-git (skip git init), --no-install (skip bun install)
Manual Setup
mkdir my-tui && cd my-tui
bun init
bun install @opentui/react @opentui/core react
TypeScript Configuration
tsconfig.json
{
"compilerOptions": {
"lib": ["ESNext", "DOM"],
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "bundler",
"jsx": "react-jsx",
"jsxImportSource": "@opentui/react",
"strict": true,
"skipLibCheck": true,
"noEmit": true,
"types": ["bun-types"]
},
"include": ["src/**/*"]
}
Critical settings:
jsx: "react-jsx"- Use the new JSX transformjsxImportSource: "@opentui/react"- Import JSX runtime from OpenTUI
Why DOM lib?
The DOM lib is needed for React types. OpenTUI's JSX types extend React's.
Package Configuration
package.json
{
"name": "my-tui-app",
"type": "module",
"scripts": {
"start": "bun run src/index.tsx",
"dev": "bun --watch run src/index.tsx",
"test": "bun test",
"build": "bun build src/index.tsx --outdir=dist --target=bun"
},
"dependencies": {
"@opentui/core": "latest",
"@opentui/react": "latest",
"react": ">=19.0.0"
},
"devDependencies": {
"@types/bun": "latest",
"@types/react": ">=19.0.0",
"typescript": "latest"
}
}
Project Structure
Recommended structure:
my-tui-app/
├── src/
│ ├── components/
│ │ ├── Header.tsx
│ │ ├── Sidebar.tsx
│ │ └── MainContent.tsx
│ ├── hooks/
│ │ └── useAppState.ts
│ ├── App.tsx
│ └── index.tsx
├── package.json
└── tsconfig.json
Entry Point (src/index.tsx)
import { createCliRenderer } from "@opentui/core"
import { createRoot } from "@opentui/react"
import { App } from "./App"
const renderer = await createCliRenderer({
exitOnCtrlC: true,
})
createRoot(renderer).render(<App />)
App Component (src/App.tsx)
import { Header } from "./components/Header"
import { Sidebar } from "./components/Sidebar"
import { MainContent } from "./components/MainContent"
export function App() {
return (
<box flexDirection="column" width="100%" height="100%">
<Header />
<box flexDirection="row" flexGrow={1}>
<Sidebar />
<MainContent />
</box>
</box>
)
}
Renderer Configuration
createCliRenderer Options
import { createCliRenderer, ConsolePosition } from "@opentui/core"
const renderer = await createCliRenderer({
// Rendering
targetFPS: 60,
// Behavior
exitOnCtrlC: true, // Set false to handle Ctrl+C yourself
// Debug console
consoleOptions: {
position: ConsolePosition.BOTTOM,
sizePercent: 30,
startInDebugMode: false,
},
// Cleanup
onDestroy: () => {
// Cleanup code
},
})
Building for Distribution
Bundling with Bun
// build.ts
await Bun.build({
entrypoints: ["./src/index.tsx"],
outdir: "./dist",
target: "bun",
minify: true,
})
Run: bun run build.ts
Creating Executables
// build.ts
await Bun.build({
entrypoints: ["./src/index.tsx"],
outdir: "./dist",
target: "bun",
compile: {
target: "bun-darwin-arm64", // or bun-linux-x64, etc.
outfile: "my-app",
},
})
Environment Variables
Create .env for development:
# Debug settings
OTUI_SHOW_STATS=false
SHOW_CONSOLE=false
# App settings
API_URL=https://api.example.com
Bun auto-loads .env files. Access via process.env:
const apiUrl = process.env.API_URL
React DevTools
OpenTUI React supports React DevTools for debugging.
Setup
-
Install DevTools as a dev dependency (must use version 7):
bun add react-devtools-core@7 -d -
Run DevTools standalone app:
npx react-devtools@7 -
Start your app with
DEV=trueenvironment variable:DEV=true bun run src/index.tsx
Important: Auto-connect to DevTools ONLY happens when DEV=true is set. Without this environment variable, the DevTools connection code is not loaded.
How It Works
OpenTUI checks for process.env["DEV"] === "true" at startup. When true, it dynamically imports react-devtools-core and connects to the standalone DevTools app.
Testing Configuration
Test Setup
// src/test-utils.tsx
import { createTestRenderer } from "@opentui/core/testing"
import { createRoot } from "@opentui/react"
export async function renderForTest(
element: React.ReactElement,
options = { width: 80, height: 24 }
) {
const testSetup = await createTestRenderer(options)
createRoot(testSetup.renderer).render(element)
return testSetup
}
Test Example
// src/components/Counter.test.tsx
import { test, expect } from "bun:test"
import { renderForTest } from "../test-utils"
import { Counter } from "./Counter"
test("Counter renders initial value", async () => {
const { snapshot } = await renderForTest(<Counter initialValue={5} />)
expect(snapshot()).toContain("Count: 5")
})
Common Issues
JSX Types Not Working
Ensure jsxImportSource is set:
{
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "@opentui/react"
}
}
React Version Mismatch
Ensure React 19+:
bun install react@19 @types/react@19
Module Resolution Errors
Use moduleResolution: "bundler" for Bun compatibility.