File types · Explainer

The TSX file (.tsx)

A TSX file is a TypeScript source file that also contains JSX, the HTML-like tags used to describe user interfaces in React and similar libraries. This guide explains what's inside one, what the tags compile to, the settings and quirks that trip people up, and has free sample TSX files to download for testing.

At a glance

Full name
TypeScript with JSX
Extensions
.tsx
MIME type
None registered; servers usually send text/plain or a generic binary type
Kind
Plain text (source code), UTF-8
Defined by
The TypeScript compiler (Microsoft) and the JSX draft specification (Meta)
Used for
Components in React, Preact, Solid and other JSX-based libraries
Compiles to
.js (tags become function calls), or .jsx with "jsx": "preserve"
Runs with
Bun, Deno and the tsx package directly; Node.js can't run .tsx on its own
Opens with
Any code editor; VS Code understands it without plugins
Magic number
None; it's text

The basics

What is a TSX file?

A .tsx file is a TypeScript file that may contain JSX. JSX is a syntax extension, created for React, that lets you write user-interface markup in the middle of code: <button onClick={save}>Save</button> instead of a chain of function calls. The .tsx extension is how the TypeScript compiler knows to expect it: in a plain .ts file, JSX is a syntax error.

Most .tsx files hold one or more components for a React app, a Next.js site or a similar project. Like every TypeScript file, it can't run as it is. A compiler or bundler removes the types and turns each tag into a JavaScript function call, and the result runs in the browser.

  • JSX isn't HTML. It's closer to JavaScript: attributes are props, {…} holds expressions, every tag must be closed (<br />), and a component returns a single element or a fragment <>…</>.
  • JSX isn't part of JavaScript. Its specification says it isn't meant to be implemented by browsers or engines, nor proposed for ECMAScript; it's meant for compilers to transform.
  • TSX isn't only React. The tags compile to whatever functions you configure, so Preact, Solid and other libraries use .tsx files too.

Anatomy

What's inside a TSX file

A TSX file is TypeScript in which an expression can also be a JSX element: a tag like <section>, with attributes and children, that a compiler turns into a function call. Here is a typical React component, part by part.

Counter.tsx
import { useState, type ReactNode } from "react";

type Props = {
  title: string;
  initial?: number;
  children?: ReactNode;
};

export function Counter({ title, initial = 0, children }: Props) {
  const [count, setCount] = useState<number>(initial);

  return (
    <section className="counter">
      <h2>{title}</h2>
      {children}
      <button onClick={() => setCount(count + 1)}>
        Clicked {count} times
      </button>
    </section>
  );
}

export const First = <T,>({ items }: { items: T[] }) => (
  <p>First: {String(items[0])}</p>
);
  1. 1import { useState, type ReactNode } from "react";

    Imports

    A hook and a type from React. With the automatic JSX runtime, the file doesn't need to import React itself just to use tags.

  2. 2type Props = { … };

    The props type

    Describes the attributes the component accepts. <Counter /> without a title, or with initial="5" as a string, is a compile error.

  3. 3children?: ReactNode;

    Children

    Whatever goes between <Counter> and </Counter>. ReactNode covers text, numbers, elements, lists and nothing.

  4. 4export function Counter(…)

    A component

    A function that takes props and returns JSX. Its name must start with a capital letter: lowercase tags are treated as HTML elements.

  5. 5useState<number>(initial)

    A typed hook

    TypeScript generics work as usual in a .tsx file when they follow a function name.

  6. 6<section className="counter">

    A JSX element

    Looks like HTML but is an expression. In React, attributes use their DOM property names: className rather than class, htmlFor rather than for.

  7. 7{title}

    An embedded expression

    Curly braces hold any TypeScript expression. Text inserted this way is escaped, so it can't inject HTML.

  8. 8onClick={() => setCount(count + 1)}

    An event handler

    A function, not a string of code as in HTML. TypeScript knows the event's type, so event.currentTarget is an HTMLButtonElement.

  9. 9<T,>({ items }: { items: T[] }) =>

    A generic arrow function

    The comma after T is needed in .tsx only: without it, <T> is read as the start of a JSX tag.

Under the hood

What the tags in a TSX file compile to

Each JSX element becomes a call to a function, with the tag name, an object of props and the children. Which function depends on the jsx compiler option. Here is the Counter component above, compiled by tsc with the two React settings:

Counter.js with "jsx": "react-jsx" (the automatic runtime)
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useState } from "react";
export function Counter({ title, initial = 0, children }) {
    const [count, setCount] = useState(initial);
    return (_jsxs("section", { className: "counter", children: [_jsx("h2", { children: title }), children, _jsxs("button", { onClick: () => setCount(count + 1), children: ["Clicked ", count, " times"] })] }));
}
Counter.js with "jsx": "react" (the classic runtime), return statement
return (React.createElement("section", { className: "counter" },
    React.createElement("h2", null, title),
    children,
    React.createElement("button", { onClick: () => setCount(count + 1) },
        "Clicked ",
        count,
        " times")));
"jsx" settingOutputFile written
react-jsx_jsx() calls, with the import from react/jsx-runtime added automatically.js
react-jsxdev_jsxDEV() calls with extra debugging information.js
reactReact.createElement() calls; React must be in scope.js
preserveThe JSX left as it is, for another tool to compile.jsx
react-nativeThe JSX left as it is.js

The automatic runtime arrived with React 17 in 2020 and is supported from TypeScript 4.1; it's what new React projects use. The classic React.createElement form still works, and it's what "jsx": "react" produces, which is why older files start with import React from "react".

Configuration

Setting up tsconfig.json for React, Preact or Solid

Two options in tsconfig.json decide how .tsx files are checked and compiled: jsx picks the output form, and jsxImportSource names the library whose runtime and types to use.

tsconfig.json (React)
{
  "compilerOptions": {
    "jsx": "react-jsx",
    "jsxImportSource": "react",
    "strict": true,
    "module": "esnext",
    "moduleResolution": "bundler",
    "noEmit": true
  }
}
Library"jsx""jsxImportSource"Note
Reactreact-jsxreact (the default)Install @types/react for the types
Preactreact-jsxpreactPreact accepts class as well as className
Solidpreservesolid-jsSolid compiles JSX with its own plugin, so TypeScript leaves it alone

A single file can override the project with a comment at the top: /** @jsxImportSource preact */ changes the library, and /** @jsxRuntime classic */ with /** @jsx h */ makes every tag call your own h() function. The sample-no-react.tsx file below uses this to run without any library.

Bundlers such as esbuild and Vite compile .tsx without checking types. Run tsc --noEmit as well, so type errors in components are caught.

Syntax

What works differently in .tsx than in .ts

Because < can now start a tag, a few TypeScript forms that use angle brackets clash with JSX:

In a .ts fileIn a .tsx fileWhy
const id = <T>(x: T) => x;const id = <T,>(x: T) => x;<T> at the start of an expression is read as an opening JSX tag. The trailing comma (or <T extends unknown>) makes it a type parameter. Generic function declarations are unaffected
const n = <number>value;const n = value as number;Angle-bracket type assertions aren't allowed in .tsx; as works in both
No JSX<div>…</div>, <Card />Lowercase names are HTML elements, checked against JSX.IntrinsicElements; capitalised names must be components in scope

Only use .tsx for files that contain JSX. Keeping utility code in .ts files avoids these clashes and makes it clear which files depend on a UI library.

Related formats

.tsx vs .ts vs .jsx vs .js

ExtensionTypesJSXTypical content
.tsxYesYesComponents written in TypeScript
`.ts`YesNo (a syntax error)Logic, utilities, server code
`.jsx`NoYesComponents written in JavaScript
`.js`NoOnly if the build tool is configured for itEverything else; the output of compiling all of the above

Moving a component from .jsx to .tsx is a rename followed by adding types for its props. The tags stay exactly the same.

How to

How to run, build and open a TSX file

  • Open or edit it: in VS Code, which understands TSX without plugins, or WebStorm, Zed or any other code editor. Any text editor shows it as plain text.
  • Build it for the browser: with the tool your project uses, such as Vite (npm run dev, npm run build), Next.js or npx esbuild app.tsx --bundle. They all compile .tsx out of the box.
  • Check types: npx tsc --noEmit with a tsconfig.json that sets jsx, or npx tsc --noEmit --jsx react-jsx file.tsx for one file.
  • Run it in a terminal: Bun (bun file.tsx) and Deno run TSX directly, and so does the tsx package on Node.js (npx tsx file.tsx). Node.js itself can strip types from .ts files but doesn't support .tsx.
  • Try it online: the TypeScript Playground on typescriptlang.org accepts TSX and shows the errors and the compiled JavaScript.

tsx the tool vs .tsx the file

The tsx npm package ("TypeScript Execute") is a command that runs TypeScript files on Node.js. It shares the name, and can run .tsx files, but it's not the file format.

Troubleshooting

The TSX errors people hit most, and what they mean

Error messageUsual causeFix
TS17004: Cannot use JSX unless the '--jsx' flag is providedNo jsx setting in tsconfig.json, or tsc file.tsx run without oneAdd "jsx": "react-jsx" (or your library's setting)
React is not definedThe classic runtime turned tags into React.createElement(), but the file never imports ReactSwitch to the automatic runtime ("jsx": "react-jsx"), or add import React from "react"
TS2686: 'React' refers to a UMD global, but the current file is a module"jsx": "react" in a file that doesn't import ReactUse "jsx": "react-jsx"
TS7026: JSX element implicitly has type 'any' because no interface 'JSX.IntrinsicElements' existsThe library's types aren't installed or foundnpm i -D @types/react (or set jsxImportSource for another library)
TS17008: JSX element 'T' has no corresponding closing tagA generic arrow function written as <T>(…) =>Write <T,>(…) =>
Unknown file extension ".tsx"Running a .tsx file with plain Node.js (outside an ES module project it shows as SyntaxError: Unexpected token '<')Use npx tsx file.tsx or Bun, or build it first

Security

Is it safe to open a TSX file?

Opening a .tsx file in an editor shows text and runs nothing. Running or building one runs code, and building a project also runs its build tools and npm packages, with your permissions. Treat a downloaded project like any program.

In the code itself, React escapes any text you insert with {…}, so a user's name can't turn into HTML or a script. The escape hatch, dangerouslySetInnerHTML, skips that protection: only pass it HTML you have sanitised or fully control, or it becomes a cross-site scripting hole.

Free downloads

Sample TSX files to download

Free sample TSX files for testing compilers, bundlers, editors, syntax highlighters, upload filters and size limits. Each .tsx file passes tsc --noEmit in strict mode and runs with tsx and Bun with the same output.

sample-component.tsx · 3.3 KBDownloadOpen
Loading…

What's inside sample-component.tsx

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-component.tsx prints the HTML it renders.

  1. The first line: the JSX runtime

    /** @jsxRuntime automatic */ makes this one file use React's automatic runtime, so it runs even without a tsconfig.json.

  2. Comments 1 to 3: imports, props and a component

    Type-only imports with the type keyword, a BadgeProps interface with a union-typed tone, and a Badge component with a default prop value.

  3. Comment 4: JSX syntax

    className, a template literal inside an attribute, and {…} for values and children.

  4. Comments 5 and 6: a generic component

    List is written <T,>(…) => so the type parameter isn't mistaken for a tag, and gives each item a key.

  5. Comment 7: state and events

    useState<number> and a click handler typed as MouseEvent<HTMLButtonElement>.

  6. Comment 8: type assertions

    JSON.parse(…) as { … }; the older <Type>value form would be a syntax error in a .tsx file.

  7. Comments 9 and 10: composition and rendering

    A fragment, a conditional, and renderToStaticMarkup to print HTML in a terminal instead of drawing in a browser.

All sample TSX files

  • Commented React components

    sample-component.tsx · 3.3 KB (3,391 bytes)

    Typed props, a generic list component, state, an event handler, a fragment and conditional rendering, with numbered comments explaining each part. Needs react, react-dom and their @types packages to run and check.

    • Checking a bundler or editor handles TSX and generics
    • Teaching typed React components
  • TSX with no library

    sample-no-react.tsx · 2.7 KB (2,807 bytes)

    Uses @jsxRuntime classic and @jsx h comments to compile its tags to calls to a small h() function that builds escaped HTML. Runs with npx tsx or bun without installing anything, and declares its own JSX types.

    • Testing JSX pragmas and custom factories
    • Seeing what JSX compiles to without React
  • sample-component.tsx after compiling

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

    The featured file compiled by TypeScript 7.0.2 with --jsx react-jsx: no types, and every tag a _jsx() or _jsxs() call. Runs with node where React is installed.

    • Comparing TSX with its JavaScript output
    • Checking a minifier or linter on compiled React code
  • 100 KB TSX file

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

    1,800 typed colour swatches rendered into an HTML table by a tiny JSX factory, 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

  • JSX settings: run sample-no-react.tsx through your bundler. If it fails while npx tsx works, the tool is ignoring the @jsx pragma comments.
  • Generics: sample-component.tsx contains a <T,> arrow function; tools that parse .tsx as plain TypeScript, or .ts as TSX, will choke on one or the other.
  • Compiled output: compile sample-component.tsx with your settings and compare it with sample-compiled.js.
  • Upload filters and limits: .tsx is unknown to many upload filters. sample-100kb.tsx 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 TSX file? Give it a link.

Drop a .tsx 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

TSX files, frequently asked

What is a .tsx file?

A TypeScript file that contains JSX, the HTML-like tags used by React and similar libraries. It usually holds user-interface components.

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

Only .tsx files may contain JSX tags. In exchange, .tsx files can't use the <Type>value assertion form, and generic arrow functions need a comma: <T,>.

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

.tsx is TypeScript with JSX, so it has type annotations that a compiler checks. .jsx is JavaScript with JSX and has no types.

How do I open a .tsx file?

In any code editor, such as VS Code, or a plain-text editor. It's text. To see what it renders, it has to be built as part of a React (or similar) project.

Can I run a .tsx file with Node.js?

Not directly: Node.js strips types from .ts files but doesn't support .tsx. Use npx tsx file.tsx, Bun or Deno, or compile it first.

Do I need to import React in a .tsx file?

Not with the automatic runtime ("jsx": "react-jsx"), which new projects use. With the classic "jsx": "react" setting, every file with JSX must import React.

Why does my generic arrow function break in a .tsx file?

<T>(x: T) => x looks like the start of a JSX tag. Write <T,>(x: T) => x or <T extends unknown>(x: T) => x.

Is TSX only for React?

No. The tags compile to whatever functions you configure, so Preact, Solid and other libraries use .tsx files too, each with its own jsxImportSource.

Related formats

Other file types explained

Keep going

Related

Sources

Last reviewed 27 October 2026.