File types · Explainer

The JSX file (.jsx)

A JSX file is a JavaScript source file that also contains JSX, the HTML-like tags React and similar libraries use to describe user interfaces. This guide explains what's inside one, why it has to be compiled before it runs, the naming conventions and errors worth knowing, and has free sample JSX files to download for testing.

At a glance

Full name
JavaScript with JSX (often expanded as JavaScript XML)
Extensions
.jsx; also found in .js files in some projects
MIME type
None registered; text/jsx appears in some server tables
Kind
Plain text (source code), UTF-8
Specification
JSX draft specification, maintained by Meta; not part of ECMAScript
Introduced
2013, with React (Facebook, now Meta); draft specification published in 2014
Compiled by
Babel, esbuild, Vite, SWC and the TypeScript compiler
Runs in
Nothing directly: browsers and Node.js need it compiled first; Bun and Deno compile it on the fly
Not to be confused with
Adobe ExtendScript scripts for Photoshop, Illustrator and other Adobe apps, which also use .jsx
Magic number
None; it's text

The basics

What is a JSX file?

A .jsx file holds JavaScript that uses JSX, a syntax extension created at Facebook (now Meta) for React. JSX lets you write user-interface markup where JavaScript expects a value: const title = <h1>Hello</h1>;. The .jsx extension tells editors and build tools to expect those tags.

Most .jsx files contain React components: App.jsx, Button.jsx, main.jsx. Preact, Solid and other libraries use JSX too. The TypeScript version, with types, is the `.tsx` file.

  • JSX isn't HTML. It turns into JavaScript function calls, so attributes are values (count={3} is a number), names follow the DOM (className), and every tag must be closed.
  • JSX isn't a template language. There are no special loops or if blocks: you use JavaScript's own map, ? : and && inside {…}.
  • JSX isn't standard JavaScript. Its specification says it isn't meant for browsers or engines to implement, nor proposed for ECMAScript. Something has to compile it first.

Anatomy

What's inside a JSX file

A JSX file is ordinary JavaScript in which an expression can also be an element written as a tag. Here is a small React component, a to-do list, part by part.

TodoList.jsx
import { useState } from "react";
import "./TodoList.css";

export default function TodoList({ initial = [] }) {
  const [items, setItems] = useState(initial);
  const [text, setText] = useState("");

  function add(event) {
    event.preventDefault();
    if (text.trim()) setItems([...items, text.trim()]);
    setText("");
  }

  return (
    <form onSubmit={add} className="todo">
      <label htmlFor="todo-text">New item</label>
      <input id="todo-text" value={text}
        onChange={(e) => setText(e.target.value)} />
      {items.length === 0 ? (
        <p>Nothing to do yet.</p>
      ) : (
        <ul>
          {items.map((item) => <li key={item}>{item}</li>)}
        </ul>
      )}
    </form>
  );
}
  1. 1import { useState } from "react";

    An ES module import

    JSX files are almost always ES modules. useState is a React hook; with the automatic JSX runtime the file doesn't import React itself to use tags.

  2. 2import "./TodoList.css";

    A stylesheet import

    Not JavaScript at all: a bundler such as Vite or webpack understands it and adds the CSS to the page. Without a bundler this line fails.

  3. 3export default function TodoList({ initial = [] })

    A component

    A function whose name starts with a capital letter. Its one argument holds the props, unpacked here with a default value.

  4. 4const [items, setItems] = useState(initial);

    State

    A value React keeps between renders. Calling setItems stores a new value and redraws the component.

  5. 5event.preventDefault();

    An event handler

    Plain JavaScript: stops the browser submitting the form and reloading the page.

  6. 6return ( <form …> … </form> );

    The returned JSX

    A component returns one root element (or a fragment <>…</>). The brackets only let the JSX span several lines.

  7. 7className="todo" / htmlFor="todo-text"

    DOM property names

    In React, class and for are written className and htmlFor, the names the browser's DOM uses, because class and for are JavaScript keywords.

  8. 8<input … />

    A self-closing tag

    Every element must be closed in JSX, including ones HTML leaves open, like <input>, <img> and <br>.

  9. 9{items.length === 0 ? ( … ) : ( … )}

    A condition

    Curly braces hold any JavaScript expression. if statements can't go inside JSX, so conditions use ? : or &&.

  10. 10<li key={item}>

    A list with keys

    map turns an array into elements. The key lets React tell items apart when the list changes.

Under the hood

Why browsers can't run a .jsx file, and what it compiles to

To a browser or Node.js, <form onSubmit={add}> is a syntax error: < is the less-than operator. Before the code can run, a compiler replaces each element with a function call that takes the tag name, an object of props and the children. Here is the return statement of the anatomy example, compiled by Babel with React's automatic runtime:

TodoList.js (Babel 8, production)
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
// …
  return /*#__PURE__*/_jsxs("form", {
    onSubmit: add,
    className: "todo",
    children: [/*#__PURE__*/_jsx("label", {
      htmlFor: "todo-text",
      children: "New item"
    }), /*#__PURE__*/_jsx("input", {
      id: "todo-text",
      value: text,
      onChange: e => setText(e.target.value)
    }), items.length === 0 ? /*#__PURE__*/_jsx("p", {
      children: "Nothing to do yet."
    }) : /*#__PURE__*/_jsx("ul", {
      children: items.map(item => /*#__PURE__*/_jsx("li", {
        children: item
      }, item))
    })]
  });

The /*#__PURE__*/ comments tell minifiers each call can be dropped if its result is unused. The older classic runtime compiles to React.createElement instead, which is why older JSX files start with import React from "react":

TodoList.js (classic runtime)
return React.createElement("form", { onSubmit: add, className: "todo" },
  React.createElement("label", { htmlFor: "todo-text" }, "New item"),
  …

React introduced the automatic runtime with React 17 in 2020 and Babel 7.9. Current Babel (version 8) uses it by default; esbuild still defaults to the classic form unless you pass --jsx=automatic or set it in tsconfig.json. The output is plain JavaScript that runs anywhere React is loaded.

For quick demos, @babel/standalone can compile JSX inside the browser from a <script type="text/babel"> element. It downloads the whole compiler and compiles on every page load, so real sites compile ahead of time.

Tools

Compiling JSX with Babel, esbuild, Vite and others

ToolCommand or setupJSX in .js files?
Babelnpx babel app.jsx --presets @babel/preset-reactYes; Babel goes by its configuration, not the extension
esbuildnpx esbuild app.jsx --bundle --jsx=automaticOnly with --loader:.js=jsx
ViteHandles .jsx and .tsx out of the box (npm create vite@latest, React template)Not by default
TypeScript (tsc)"allowJs": true and a "jsx" setting in tsconfig.jsonYes, with allowJs
Bunbun app.jsx runs it directlyYes
Node.jsCan't run .jsx; compile first, or use npx tsx app.jsxNo

Vite's own React template names its files main.jsx and App.jsx. Whatever the tool, the output is the same kind of file: plain JavaScript in which every tag has become a function call.

Naming

.jsx vs .js: which extension to use

Both conventions exist. Create React App and many older projects put JSX in .js files and configured their tools to accept it. Vite, esbuild and most current setups expect JSX in .jsx (or .tsx) files and plain JavaScript in .js, and the popular ESLint React plugin has a rule, react/jsx-filename-extension, that enforces the same.

ConventionTypical filesWhy
JSX only in .jsxApp.jsx, Button.jsx, api.js, utils.jsTools and readers know which files contain markup; fastest builds
JSX in .jsApp.js, Button.jsOlder React projects; needs the build tool configured
TypeScriptApp.tsx, api.tsSame split, with types; the default in many new projects

Component files are usually named after the component, in PascalCase (TodoList.jsx exports TodoList), with one main component per file. Renaming .js to .jsx changes nothing in the code; check that imports which spell out the extension are updated.

Same extension

The other .jsx: Adobe ExtendScript

Adobe apps such as Photoshop, Illustrator and InDesign run automation scripts written in ExtendScript, Adobe's older dialect of JavaScript, and those scripts also use the .jsx extension. They have nothing to do with React. Telling them apart:

React JSXAdobe ExtendScript
Contains<tags>, import, componentsNo tags; app.activeDocument, File, alert()
Often starts withimport linesA #target photoshop (or other app) line
Runs inA browser, after compilingThe Adobe app: File > Scripts
Compiled form.js.jsxbin (binary)

An ExtendScript .jsx file is a full program inside the Adobe app: it can read, write and delete files on your computer. Only run scripts from sources you trust.

Troubleshooting

The JSX errors people hit most, and what they mean

Error messageUsual causeFix
SyntaxError: Unexpected token '<'A .jsx file (or JSX in a .js file) loaded straight into a browser or Node.jsCompile it with a build tool first
Unknown file extension ".jsx"node file.jsx in an ES module projectBuild it first, or run it with npx tsx file.jsx or Bun
The JSX syntax extension is not currently enabledesbuild (or Vite) reading JSX in a .js fileRename it to .jsx, or pass --loader:.js=jsx
Support for the experimental syntax 'jsx' isn't currently enabledBabel without @babel/preset-reactAdd the preset to the Babel configuration
React is not definedThe classic runtime turned tags into React.createElement(), but the file doesn't import ReactUse the automatic runtime, or add import React from "react"
Adjacent JSX elements must be wrapped in an enclosing tagA component returning two sibling elementsWrap them in a parent element or a fragment <>…</>

How to

How to open and edit a JSX file, and is it safe?

  • Edit it: VS Code highlights and checks JSX without plugins; WebStorm, Zed, Sublime Text and other code editors support it too. Any text editor can open it.
  • See what it renders: it has to run inside a project: npm create vite@latest, pick React, put the component in src, and run npm run dev.
  • Run a single file in a terminal: bun file.jsx, or npx tsx file.jsx on Node.js. The samples below print their HTML this way.
  • Convert it to plain JavaScript: npx babel file.jsx --presets @babel/preset-react or npx esbuild file.jsx --jsx=automatic.

Opening a .jsx file in an editor runs nothing. A React project's build runs its tools and npm packages with your permissions, so treat a downloaded project like any program. In the code, React escapes text inserted with {…}; dangerouslySetInnerHTML skips that, so only pass it HTML you have sanitised or fully control. And remember that an Adobe .jsx script is a program for Photoshop or Illustrator, not a web component.

Free downloads

Sample JSX files to download

Free sample JSX files for testing compilers, bundlers, syntax highlighters, encodings, upload filters and size limits. Each was compiled with Babel or esbuild and run with Bun and, where Node.js allows, tsx, with matching output.

sample-app.jsx · 2.6 KBDownloadOpen
Loading…

What's inside sample-app.jsx

The file is commented: open it in a text editor and each numbered comment marks one of these parts. With React installed, npx tsx sample-app.jsx prints the HTML it renders.

  1. The header and pragma

    How to set up, run and build the file, and a /** @jsxRuntime automatic */ comment so it compiles the same way in every tool.

  2. Comments 1 and 2: imports and a component

    Only useState is imported from React. Greeting takes props with a default value for lang.

  3. Comments 3 and 4: JSX syntax

    className, a self-closing <br />, an expression choosing the greeting, and a comment written inside JSX with {/* … */}.

  4. Comment 5: lists

    map over an array of menu items, each <li> with a key.

  5. Comment 6: state and events

    A like button with useState, an onClick arrow function and an aria-pressed attribute.

  6. Comments 7 and 8: composition and rendering

    A fragment holding several components, && to show the menu only when it has items, and renderToStaticMarkup to print HTML in a terminal.

All sample JSX files

  • Commented React components

    sample-app.jsx · 2.6 KB (2,704 bytes)

    Props, lists with keys, state, an event handler, a fragment and conditional rendering, with numbered comments explaining each part. Needs react and react-dom installed to run.

    • Checking a bundler, linter or highlighter handles JSX
    • Teaching React components
  • sample-app.jsx after compiling

    sample-compiled.js · 3.3 KB (3,427 bytes)

    The featured file compiled by Babel 8 with @babel/preset-react for production: the same comments, and every tag now a _jsx() or _jsxs() call.

    • Seeing what JSX turns into
    • Comparing your build's output
  • JSX in a .js file

    sample-jsx-in-js.js · 1.2 KB (1,262 bytes)

    JSX in a file with a .js extension, as some projects do. node and a default esbuild reject it; esbuild --loader:.js=jsx builds it. Uses a tiny h() factory, so it needs no React.

    • Testing how tools treat JSX in `.js` files
    • Checking lint rules about file extensions
  • UTF-8 with BOM and CRLF

    sample-utf8.jsx · 1.5 KB (1,499 bytes)

    Text in ten languages, including right-to-left Arabic and Hebrew, emoji, and HTML entities inside JSX (&euro;, &nbsp;), saved with a UTF-8 byte order mark and Windows line endings. Needs no React.

    • Spotting encoding bugs in compilers and pipelines
    • Testing BOM and CRLF handling
  • 100 KB JSX file

    sample-100kb.jsx · 100 KB (102,400 bytes)

    A table of 823 Latin, Greek and Cyrillic letters with their Unicode names, rendered by a tiny JSX factory and padded with comments to exactly 102,400 bytes. Needs no npm packages.

    • Upload and size-limit tests
    • Compiler and highlighter performance

Ways to test with them

  • Encodings: run sample-utf8.jsx through your build and compare the output. Any à or †means a step didn't read it as UTF-8; a stray  at the start means the byte order mark wasn't stripped.
  • Loader settings: sample-jsx-in-js.js should fail in a default esbuild or Vite setup and build once JSX is enabled for .js.
  • Compiler output: compile sample-app.jsx with your settings and compare it with sample-compiled.js.
  • Upload filters and limits: some filters block .jsx (it's also an Adobe script extension). sample-100kb.jsx is exactly 102,400 bytes, for testing a limit at the boundary.

Free to use for testing, teaching and demos, commercially or not, with no attribution needed. A link back to this page is always appreciated.

Put it online

Have a JSX file? Give it a link.

Drop a .jsx file on 99helpers and it gets its own address in seconds. Opening the link shows the code as plain text in the browser, and it never runs, which is what you want for sharing a component's source.

Questions

JSX files, frequently asked

What is a .jsx file?

Usually a JavaScript file that contains JSX, the HTML-like tags used by React. It holds user-interface components and is compiled to plain JavaScript before it runs. Some .jsx files are Adobe ExtendScript scripts instead.

What does JSX stand for?

It's commonly expanded as JavaScript XML, after the XML-like syntax of its tags. React's documentation just calls it JSX, a syntax extension for JavaScript.

How do I open a .jsx file?

In any code editor, such as VS Code, or a plain-text editor: it's text. To see what it renders, run it as part of a React project, for example one created with Vite.

Can a browser run a .jsx file?

No. Browsers only understand JavaScript, and the tags are a syntax error to them. A build tool such as Vite, esbuild or Babel compiles JSX to JavaScript first.

Should I use .jsx or .js for React components?

.jsx is the safer choice today: Vite and esbuild expect JSX in .jsx files by default. JSX in .js files works only where the build tool is configured for it, as in Create React App.

What's the difference between .jsx and .tsx?

.tsx is the TypeScript version: the same tags, plus type annotations checked by the TypeScript compiler.

How do I convert a .jsx file to .js?

Compile it: npx babel file.jsx --presets @babel/preset-react or npx esbuild file.jsx --jsx=automatic. Renaming it to .js doesn't remove the tags.

Why does my Photoshop script have a .jsx extension?

Adobe apps use .jsx for ExtendScript, their own scripting dialect of JavaScript. Those files have nothing to do with React, and they run inside the Adobe app.

Related formats

Other file types explained

Keep going

Related

Sources

Last reviewed 27 October 2026.