> ## 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.

# JSX

> JSX and TSX transformation in Bun

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:

```bash Run JSX theme={null}
bun run App.jsx
bun run Component.tsx
```

No Babel, no webpack needed.

## JSX Transformation

Bun transforms JSX elements into function calls:

```jsx JSX input theme={null}
const element = <div className="container">Hello</div>;
```

```javascript Output (classic runtime) theme={null}
const element = React.createElement("div", { className: "container" }, "Hello");
```

```javascript Output (automatic runtime) theme={null}
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:

```jsx Classic runtime theme={null}
import React from "react";

function Button({ children }) {
  return <button className="btn">{children}</button>;
}
```

**Transformed to:**

```javascript theme={null}
import React from "react";

function Button({ children }) {
  return React.createElement("button", { className: "btn" }, children);
}
```

**Configuration:**

```json tsconfig.json theme={null}
{
  "compilerOptions": {
    "jsx": "react"
  }
}
```

### Automatic Runtime (react/jsx-runtime)

Modern React 17+ runtime:

```jsx Automatic runtime theme={null}
// No React import needed!
function Button({ children }) {
  return <button className="btn">{children}</button>;
}
```

**Transformed to:**

```javascript theme={null}
import { jsx as _jsx } from "react/jsx-runtime";

function Button({ children }) {
  return _jsx("button", { className: "btn", children });
}
```

**Configuration:**

```json tsconfig.json theme={null}
{
  "compilerOptions": {
    "jsx": "react-jsx",
    "jsxImportSource": "react"
  }
}
```

### Development Runtime

Includes debug information:

```json tsconfig.json theme={null}
{
  "compilerOptions": {
    "jsx": "react-jsxdev"
  }
}
```

Adds `__source` and `__self` props for better debugging.

### Preserve

Leaves JSX unchanged (for further processing):

```json tsconfig.json theme={null}
{
  "compilerOptions": {
    "jsx": "preserve"
  }
}
```

## Configuration

### tsconfig.json

Configure JSX behavior:

```json tsconfig.json theme={null}
{
  "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:

```typescript Runtime JSX config theme={null}
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

```json tsconfig.json theme={null}
{
  "compilerOptions": {
    "jsx": "react-jsx",
    "jsxImportSource": "preact"
  }
}
```

```jsx Preact JSX theme={null}
import { render } from "preact";

function App() {
  return <div>Hello Preact!</div>;
}

render(<App />, document.body);
```

### Custom h() function

```json tsconfig.json theme={null}
{
  "compilerOptions": {
    "jsx": "react",
    "jsxFactory": "h",
    "jsxFragmentFactory": "Fragment"
  }
}
```

```jsx Custom h() function theme={null}
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

```json tsconfig.json theme={null}
{
  "compilerOptions": {
    "jsx": "preserve",
    "jsxImportSource": "vue"
  }
}
```

### Solid.js

```json tsconfig.json theme={null}
{
  "compilerOptions": {
    "jsx": "preserve",
    "jsxImportSource": "solid-js"
  }
}
```

## JSX Features

### Children

```jsx JSX children theme={null}
// 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

```jsx Fragments theme={null}
import { Fragment } from "react";

// Explicit Fragment
<Fragment>
  <div>First</div>
  <div>Second</div>
</Fragment>

// Short syntax
<>
  <div>First</div>
  <div>Second</div>
</>
```

### Spread Attributes

```jsx Spread attributes theme={null}
const props = { className: "btn", disabled: true };

<button {...props}>Click</button>
// Becomes: <button className="btn" disabled={true}>Click</button>
```

### Conditional Rendering

```jsx Conditional rendering theme={null}
// Ternary
{isLoggedIn ? <UserPanel /> : <LoginForm />}

// Logical AND
{isAdmin && <AdminPanel />}

// Nullish coalescing
{userName ?? "Guest"}
```

### Event Handlers

```jsx Event handlers theme={null}
<button onClick={() => console.log("clicked")}>Click</button>

<input onChange={(e) => setValue(e.target.value)} />
```

### Ref Attributes

```jsx Refs theme={null}
import { useRef } from "react";

function Input() {
  const ref = useRef<HTMLInputElement>(null);
  
  return <input ref={ref} />;
}
```

### Namespaced Attributes

```jsx Namespaced attributes theme={null}
<svg>
  <use xlinkHref="#icon" />
</svg>

// Custom namespaces
<div data-test-id="button" aria-label="Submit" />
```

## TypeScript + JSX (TSX)

Combine TypeScript types with JSX:

```tsx TypeScript JSX theme={null}
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

```tsx Generic components theme={null}
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

```tsx Type assertions theme={null}
// Generic components
const div = <div /> as React.ReactElement<HTMLDivElement>;

// Type casting
const input = <input type="text" /> as HTMLInputElement;
```

## JSX Performance

### Automatic Import Optimization

Bun automatically imports JSX functions only when needed:

```jsx Automatic imports theme={null}
// 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

```jsx Static optimization theme={null}
// 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:

```jsx React Fast Refresh theme={null}
// Automatically detected
export default function Counter() {
  const [count, setCount] = useState(0);
  return <button onClick={() => setCount(count + 1)}>{count}</button>;
}
```

**Enable Fast Refresh:**

```bash theme={null}
bun run --hot app.tsx
```

Implementation: `src/runtime.zig:147` - React Fast Refresh feature flag

## JSX Outside React

Use JSX with any virtual DOM library:

### Minimal JSX Runtime

```typescript Custom JSX runtime theme={null}
// 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;
```

```json tsconfig.json theme={null}
{
  "compilerOptions": {
    "jsx": "react-jsx",
    "jsxImportSource": "./jsx-runtime"
  }
}
```

### DOM JSX

Create real DOM elements:

```typescript DOM JSX theme={null}
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

### Inspecting Transformed Code

```bash View transpiled output theme={null}
bun build app.jsx --target=bun --format=esm > output.js
cat output.js
```

### Source Maps

Bun generates inline source maps for JSX:

```jsx Original source theme={null}
function App() {
  return <div>Hello</div>;
}
```

Debugger shows original JSX, not transformed JavaScript.

### JSX Debug Mode

```bash Debug JSX transform theme={null}
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

```zig Runtime JSX configuration (src/runtime.zig:159) theme={null}
auto_import_jsx: bool = false,
```

## Common Patterns

### Conditional Class Names

```jsx Conditional classes theme={null}
function Button({ primary, disabled }) {
  return (
    <button
      className={[
        "btn",
        primary && "btn-primary",
        disabled && "btn-disabled",
      ].filter(Boolean).join(" ")}
    >
      Click
    </button>
  );
}
```

### Render Props

```jsx Render props theme={null}
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

```jsx Component composition theme={null}
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

```bash Error theme={null}
ReferenceError: React is not defined
```

**Solution:** Use automatic runtime or import React:

```json tsconfig.json theme={null}
{
  "compilerOptions": {
    "jsx": "react-jsx"
  }
}
```

Or:

```jsx theme={null}
import React from "react";
```

### JSX not transforming

Ensure file has `.jsx` or `.tsx` extension:

```bash theme={null}
# 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.

## Related

* [TypeScript](/runtime/typescript) - TSX configuration
* [Loaders](/runtime/loaders) - JSX loader details
* [Watch Mode](/runtime/watch-mode) - Hot reload with JSX
* [React Fast Refresh](https://react.dev/learn/fast-refresh) - React docs
