JSX

Built-in JSX and TSX support in Bun with configurable transpilation options

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

react.tsx
function Component(props: {message: string}) {
  return (
    <body>
      <h1 style={{color: 'red'}}>{props.message}</h1>
    </body>
  );
}

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

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.

Bun respects the following compiler options.

jsx#

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

<Box width={5}>Hello</Box>
Compiler optionsTranspiled 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/>

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#

Only applicable when jsx is react.

The function name used to represent JSX constructs. Default value is "React.createElement". Set this for libraries like Preact that use a different function name ("h").

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

jsxFragmentFactory#

Only applicable when jsx is react.

The function name used to represent JSX fragments such as <>Hello</>. Default value is "React.Fragment".

Compiler optionsTranspiled 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#

Only applicable when jsx is react-jsx or react-jsxdev.

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

Compiler optionsTranspiled 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#

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

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

Bun implements special logging for JSX to help with debugging. Given the following file:

index.tsx
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:

JSX logging output

Prop punning#

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

react.tsx
function Div(props: {className: string;}) {
  const {className} = props;

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