# JSX (/docs/runtime/jsx)

<!-- agent-signals: reading_time_min: 3 · est_tokens: 2343 · updated: 2026-07-28 -->
Related: [Watch Mode](/docs/runtime/watch-mode.md), [Debugging](/docs/runtime/debugger.md), [REPL](/docs/runtime/repl.md), [bunfig.toml](/docs/runtime/bunfig.md), [File Types](/docs/runtime/file-types.md), [Module Resolution](/docs/runtime/module-resolution.md)

Bun supports `.jsx` and `.tsx` files. Bun's internal transpiler converts JSX syntax into vanilla JavaScript before execution.

```ts react.tsx icon="/icons/typescript.svg"
function Component(props: {message: string}) {
  return (
    <body>
      <h1 style={{color: 'red'}}>{props.message}</h1>
    </body>
  );
}

console.log(<Component message="Hello world!" />);
```

## Configuration [#configuration]

Bun reads your `tsconfig.json` or `jsconfig.json` to determine how to perform the JSX transform internally. If you'd rather not use either, you can set the same options in [`bunfig.toml`](/runtime/bunfig).

Bun respects the following compiler options.

### [`jsx`](https://www.typescriptlang.org/tsconfig#jsx) [#jsx]

How JSX constructs are transformed into vanilla JavaScript internally. The following table lists the possible values of `jsx`, along with how each transpiles this JSX component:

```tsx
<Box width={5}>Hello</Box>
```

| Compiler options                                    | Transpiled output                                                                                                                                                                                                                                                                                                                                                                                                         |
| --------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `json<br/>{<br/>  "jsx": "react"<br/>}<br/>`        | `tsx<br/>React.createElement(Box, { width: 5 }, "Hello");<br/>`                                                                                                                                                                                                                                                                                                                                                           |
| `json<br/>{<br/>  "jsx": "react-jsx"<br/>}<br/>`    | `tsx<br/>import { jsx } from "react/jsx-runtime";<br/>jsx("Box", { width: 5 }, "Hello");<br/>`                                                                                                                                                                                                                                                                                                                            |
| `json<br/>{<br/>  "jsx": "react-jsxdev"<br/>}<br/>` | `tsx<br/>import { jsxDEV } from "react/jsx-dev-runtime";<br/>jsxDEV(<br/>  "Box",<br/>  { width: 5, children: "Hello" },<br/>  undefined,<br/>  false,<br/>  undefined,<br/>  this,<br/>);<br/>`<br /><br />The `jsxDEV` variable name is a React convention. The `DEV` suffix marks code intended for development. The development version of React is slower and includes additional validity checks & debugging tools. |
| `json<br/>{<br/>  "jsx": "preserve"<br/>}<br/>`     | `tsx<br/>// JSX is not transpiled<br/>// "preserve" is not supported by Bun currently<br/><Box width={5}>Hello</Box><br/>`                                                                                                                                                                                                                                                                                                |

### [`jsxFactory`](https://www.typescriptlang.org/tsconfig#jsxFactory) [#jsxfactory]

<Note>
  Only applicable when 

  `jsx`

   is 

  `react`

  .
</Note>

The function name used to represent JSX constructs. Default value is `"React.createElement"`. Set this for libraries like [Preact](https://preactjs.com/) that use a different function name (`"h"`).

| Compiler options                                                      | Transpiled output                             |
| --------------------------------------------------------------------- | --------------------------------------------- |
| `json<br/>{<br/>  "jsx": "react",<br/>  "jsxFactory": "h"<br/>}<br/>` | `tsx<br/>h(Box, { width: 5 }, "Hello");<br/>` |

### [`jsxFragmentFactory`](https://www.typescriptlang.org/tsconfig#jsxFragmentFactory) [#jsxfragmentfactory]

<Note>
  Only applicable when 

  `jsx`

   is 

  `react`

  .
</Note>

The function name used to represent [JSX fragments](https://react.dev/reference/react/Fragment) such as `<>Hello</>`. Default value is `"React.Fragment"`.

| Compiler options                                                                                                    | Transpiled output                                                                                |
| ------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
| `json<br/>{<br/>  "jsx": "react",<br/>  "jsxFactory": "myjsx",<br/>  "jsxFragmentFactory": "MyFragment"<br/>}<br/>` | `tsx<br/>// input<br/><>Hello</>;<br/><br/>// output<br/>myjsx(MyFragment, null, "Hello");<br/>` |

### [`jsxImportSource`](https://www.typescriptlang.org/tsconfig#jsxImportSource) [#jsximportsource]

<Note>
  Only applicable when 

  `jsx`

   is 

  `react-jsx`

   or 

  `react-jsxdev`

  .
</Note>

The module the component factory function (such as `createElement`, `jsx`, or `jsxDEV`) is imported from. Default value is `"react"`. You'll typically need this when using a component library like Preact.

| Compiler options                                                                                                       | Transpiled output                                                                                                                                                                                                                               |
| ---------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `jsonc<br/>{<br/>  "jsx": "react-jsx",<br/>  // jsxImportSource is not defined<br/>  // default to "react"<br/>}<br/>` | `tsx<br/>import { jsx } from "react/jsx-runtime";<br/>jsx("Box", { width: 5, children: "Hello" });<br/>`                                                                                                                                        |
| `jsonc<br/>{<br/>  "jsx": "react-jsx",<br/>  "jsxImportSource": "preact",<br/>}<br/>`                                  | `tsx<br/>import { jsx } from "preact/jsx-runtime";<br/>jsx("Box", { width: 5, children: "Hello" });<br/>`                                                                                                                                       |
| `jsonc<br/>{<br/>  "jsx": "react-jsxdev",<br/>  "jsxImportSource": "preact",<br/>}<br/>`                               | `tsx<br/>// /jsx-runtime is automatically appended<br/>import { jsxDEV } from "preact/jsx-dev-runtime";<br/>jsxDEV(<br/>  "Box",<br/>  { width: 5, children: "Hello" },<br/>  undefined,<br/>  false,<br/>  undefined,<br/>  this,<br/>);<br/>` |

### JSX pragma [#jsx-pragma]

You can set any of these values per file with a *pragma*, a comment that sets a compiler option in a particular file.

| Pragma                                   | Equivalent config                                                  |
| ---------------------------------------- | ------------------------------------------------------------------ |
| `ts<br/>// @jsx h<br/>`                  | `jsonc<br/>{<br/>  "jsxFactory": "h",<br/>}<br/>`                  |
| `ts<br/>// @jsxFrag MyFragment<br/>`     | `jsonc<br/>{<br/>  "jsxFragmentFactory": "MyFragment",<br/>}<br/>` |
| `ts<br/>// @jsxImportSource preact<br/>` | `jsonc<br/>{<br/>  "jsxImportSource": "preact",<br/>}<br/>`        |

## Logging [#logging]

Bun implements special logging for JSX to make debugging easier. Given the following file:

```tsx index.tsx icon="/icons/typescript.svg"
import { Stack, UserCard } from "./components";

console.log(
  <Stack>
    <UserCard name="Dom" bio="Street racer and Corona lover" />
    <UserCard name="Jakob" bio="Super spy and Dom's secret brother" />
  </Stack>,
);
```

Bun pretty-prints the component tree:

<Frame>
  ![JSX logging output](https://github.com/oven-sh/bun/assets/3084745/d29db51d-6837-44e2-b8be-84fc1b9e9d97)
</Frame>

## Prop punning [#prop-punning]

The Bun runtime also supports "prop punning" for JSX: a shorthand for assigning a variable to a prop with the same name.

```tsx react.tsx icon="/icons/typescript.svg"
function Div(props: {className: string;}) {
  const {className} = props;

  // without punning
  return <div className={className} />;
  // with punning
  return <div {className} />;
}
```
