Documentation Index
Fetch the complete documentation index at: https://mintlify.com/zhcndoc/bun/llms.txt
Use this file to discover all available pages before exploring further.
Bun natively supports JSX and TSX syntax without requiring a separate build step. JSX is transformed to JavaScript function calls at runtime.
Quick Start
Run JSX/TSX files directly:
bun run App.jsx
bun run Component.tsx
No Babel, no webpack needed.
Bun transforms JSX elements into function calls:
const element = <div className="container">Hello</div>;
const element = React.createElement("div", { className: "container" }, "Hello");
Output (automatic runtime)
import { jsx as _jsx } from "react/jsx-runtime";
const element = _jsx("div", { className: "container", children: "Hello" });
JSX Runtimes
Bun supports multiple JSX transformation modes:
Classic Runtime (React.createElement)
Default behavior for React:
import React from "react";
function Button({ children }) {
return <button className="btn">{children}</button>;
}
Transformed to:
import React from "react";
function Button({ children }) {
return React.createElement("button", { className: "btn" }, children);
}
Configuration:
{
"compilerOptions": {
"jsx": "react"
}
}
Automatic Runtime (react/jsx-runtime)
Modern React 17+ runtime:
// No React import needed!
function Button({ children }) {
return <button className="btn">{children}</button>;
}
Transformed to:
import { jsx as _jsx } from "react/jsx-runtime";
function Button({ children }) {
return _jsx("button", { className: "btn", children });
}
Configuration:
{
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "react"
}
}
Development Runtime
Includes debug information:
{
"compilerOptions": {
"jsx": "react-jsxdev"
}
}
Adds __source and __self props for better debugging.
Preserve
Leaves JSX unchanged (for further processing):
{
"compilerOptions": {
"jsx": "preserve"
}
}
Configuration
tsconfig.json
Configure JSX behavior:
{
"compilerOptions": {
// JSX transformation mode
"jsx": "react-jsx",
// Factory function (classic runtime)
"jsxFactory": "h",
// Fragment factory (classic runtime)
"jsxFragmentFactory": "Fragment",
// Import source (automatic runtime)
"jsxImportSource": "preact"
}
}
Runtime Configuration
Override JSX settings programmatically:
import { Transpiler } from "bun";
const transpiler = new Transpiler({
loader: "tsx",
jsxFactory: "h",
jsxFragment: "Fragment",
jsxImportSource: "preact",
});
const code = transpiler.transformSync(source);
Custom JSX Factories
Use JSX with any framework:
Preact
{
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "preact"
}
}
import { render } from "preact";
function App() {
return <div>Hello Preact!</div>;
}
render(<App />, document.body);
Custom h() function
{
"compilerOptions": {
"jsx": "react",
"jsxFactory": "h",
"jsxFragmentFactory": "Fragment"
}
}
function h(type, props, ...children) {
return { type, props: { ...props, children } };
}
function Fragment({ children }) {
return children;
}
const vdom = <div>Custom JSX</div>;
console.log(vdom); // { type: "div", props: { children: "Custom JSX" } }
Vue JSX
{
"compilerOptions": {
"jsx": "preserve",
"jsxImportSource": "vue"
}
}
Solid.js
{
"compilerOptions": {
"jsx": "preserve",
"jsxImportSource": "solid-js"
}
}
JSX Features
Children
// Single child
<div>Hello</div>
// Multiple children
<div>
<span>First</span>
<span>Second</span>
</div>
// Expression children
<div>{user.name}</div>
// Array children
<ul>
{items.map(item => <li key={item.id}>{item.name}</li>)}
</ul>
Fragments
import { Fragment } from "react";
// Explicit Fragment
<Fragment>
<div>First</div>
<div>Second</div>
</Fragment>
// Short syntax
<>
<div>First</div>
<div>Second</div>
</>
Spread Attributes
const props = { className: "btn", disabled: true };
<button {...props}>Click</button>
// Becomes: <button className="btn" disabled={true}>Click</button>
Conditional Rendering
// Ternary
{isLoggedIn ? <UserPanel /> : <LoginForm />}
// Logical AND
{isAdmin && <AdminPanel />}
// Nullish coalescing
{userName ?? "Guest"}
Event Handlers
<button onClick={() => console.log("clicked")}>Click</button>
<input onChange={(e) => setValue(e.target.value)} />
Ref Attributes
import { useRef } from "react";
function Input() {
const ref = useRef<HTMLInputElement>(null);
return <input ref={ref} />;
}
Namespaced Attributes
<svg>
<use xlinkHref="#icon" />
</svg>
// Custom namespaces
<div data-test-id="button" aria-label="Submit" />
TypeScript + JSX (TSX)
Combine TypeScript types with JSX:
interface ButtonProps {
variant: "primary" | "secondary";
onClick: () => void;
children: React.ReactNode;
}
function Button({ variant, onClick, children }: ButtonProps) {
return (
<button className={`btn-${variant}`} onClick={onClick}>
{children}
</button>
);
}
// Type-safe usage
<Button variant="primary" onClick={() => {}}>
Click me
</Button>
Generic Components
interface ListProps<T> {
items: T[];
renderItem: (item: T) => JSX.Element;
}
function List<T>({ items, renderItem }: ListProps<T>) {
return <ul>{items.map(renderItem)}</ul>;
}
<List
items={[1, 2, 3]}
renderItem={(n) => <li key={n}>{n}</li>}
/>
Type Assertions in JSX
// Generic components
const div = <div /> as React.ReactElement<HTMLDivElement>;
// Type casting
const input = <input type="text" /> as HTMLInputElement;
Automatic Import Optimization
Bun automatically imports JSX functions only when needed:
// Input
function Component() {
return <div>Hello</div>;
}
// Output (automatic runtime)
import { jsx as _jsx } from "react/jsx-runtime";
function Component() {
return _jsx("div", { children: "Hello" });
}
No imports added if no JSX in file.
Static Children Optimization
// Multiple children optimized
<div>
<span>A</span>
<span>B</span>
</div>
// Uses jsxs() for static children array
import { jsxs as _jsxs } from "react/jsx-runtime";
_jsxs("div", { children: [_jsx("span", { children: "A" }), _jsx("span", { children: "B" })] });
React Fast Refresh
Bun supports React Fast Refresh for hot reloading:
// Automatically detected
export default function Counter() {
const [count, setCount] = useState(0);
return <button onClick={() => setCount(count + 1)}>{count}</button>;
}
Enable Fast Refresh:
Implementation: src/runtime.zig:147 - React Fast Refresh feature flag
JSX Outside React
Use JSX with any virtual DOM library:
Minimal JSX Runtime
// jsx-runtime.ts
export function jsx(type: string, props: any) {
return { type, props };
}
export function jsxs(type: string, props: any) {
return { type, props };
}
export const Fragment = ({ children }: any) => children;
{
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "./jsx-runtime"
}
}
DOM JSX
Create real DOM elements:
function h(type: string, props: any, ...children: any[]) {
const el = document.createElement(type);
Object.assign(el, props);
children.forEach(child => {
if (typeof child === "string") {
el.appendChild(document.createTextNode(child));
} else {
el.appendChild(child);
}
});
return el;
}
// Usage
const app = <div className="app">Hello!</div>;
document.body.appendChild(app);
Debugging JSX
bun build app.jsx --target=bun --format=esm > output.js
cat output.js
Source Maps
Bun generates inline source maps for JSX:
function App() {
return <div>Hello</div>;
}
Debugger shows original JSX, not transformed JavaScript.
JSX Debug Mode
BUN_DEBUG_QUIET_LOGS=0 bun run app.jsx 2>&1 | grep -i jsx
Implementation
JSX transformation implementation:
- Parser:
src/js_parser.zig - Parses JSX syntax
- Printer:
src/js_printer.zig - Generates function calls
- Runtime:
src/runtime.zig:159 - Auto-import JSX configuration
- Options:
src/options.zig - JSX pragma configuration
Feature Flags
Runtime JSX configuration (src/runtime.zig:159)
auto_import_jsx: bool = false,
Common Patterns
Conditional Class Names
function Button({ primary, disabled }) {
return (
<button
className={[
"btn",
primary && "btn-primary",
disabled && "btn-disabled",
].filter(Boolean).join(" ")}
>
Click
</button>
);
}
Render Props
interface DataFetcherProps<T> {
url: string;
children: (data: T) => JSX.Element;
}
function DataFetcher<T>({ url, children }: DataFetcherProps<T>) {
const [data, setData] = useState<T | null>(null);
useEffect(() => {
fetch(url).then(r => r.json()).then(setData);
}, [url]);
return data ? children(data) : <div>Loading...</div>;
}
// Usage
<DataFetcher url="/api/users">
{(users) => <ul>{users.map(u => <li key={u.id}>{u.name}</li>)}</ul>}
</DataFetcher>
Component Composition
function Card({ title, children }) {
return (
<div className="card">
<h2>{title}</h2>
<div className="card-body">{children}</div>
</div>
);
}
function App() {
return (
<Card title="Welcome">
<p>This is the card content</p>
</Card>
);
}
Troubleshooting
React is not defined
ReferenceError: React is not defined
Solution: Use automatic runtime or import React:
{
"compilerOptions": {
"jsx": "react-jsx"
}
}
Or:
import React from "react";
Ensure file has .jsx or .tsx extension:
# Won't transform
bun run app.js
# Will transform
bun run app.jsx
Custom pragma not working
Check tsconfig.json is in project root and properly formatted.