JSX is an XML-like syntax extension to JavaScript, developed by the React team for declaratively describing user interfaces. Unlike template engines, JSX compiles into regular JavaScript function calls, giving the full power of the language within markup. According to React, 2024, JSX is supported in all modern React frameworks and libraries.
Key Takeaways
JSX (JavaScript XML) is a syntax extension for JavaScript, first introduced in React in 2013. It allows developers to describe the structure of a user interface in a declarative style, combining markup and logic in one file.
Before JSX, developers used string templates (Mustache, Handlebars) or created DOM elements manually via document.createElement. Both approaches had drawbacks: string templates were not type-checked, and manual DOM creation was cumbersome and error-prone.
React chose a different path — embedding markup directly in code. This decision sparked debate in the community, but over time it became the standard. Today JSX is used not only in React, but also in SolidJS, Preact, Qwik and even in Vue through plugins.
A JSX element looks like an HTML tag but is embedded directly in JavaScript. Each element is transpiled into a React.createElement call with three arguments: element type, props object, and children. One root element is a mandatory rule: a JSX expression must return one parent element or fragment.
import React from 'react';
// Basic JSX - single root element
const element = (
<div className="app">
<h1>Hello, World!</h1>
<p>Welcome to React</p>
</div>
);
When no extra DOM node is needed, use React.Fragment or the shorthand syntax <></>. Fragments do not create a real DOM element, they only group child nodes. This is especially useful in tables and lists where an extra wrapper would break the HTML structure.
function Columns() {
return (
<>
<td>First</td>
<td>Second</td>
</>
);
}
Any JavaScript expression is embedded in JSX via curly braces { }. Inside, you can use variables, function calls, ternary operators, and array methods. Conditional rendering is done via the ternary operator or logical AND.
function Greeting({ name, isLoggedIn }) {
const items = ['Red', 'Green', 'Blue'];
return (
<div>
{/* Expression with variable */}
<h1>Hello, {name}</h1>
{/* Conditional rendering */}
{isLoggedIn ?
<p>Welcome back!</p :
<button>Login</button>
}
{/* Render array */}
<ul>
{items.map(item =>
<li key={item}>{item}</li>
)}
</ul>
</div>
);
}
A key limitation — only expressions can be used inside curly braces, not statements. You cannot use if/else, for, switch — only the ternary operator, logical operators, and array methods. Function calls are allowed, including arrow functions.
JSX visually resembles HTML but has fundamental differences. Attributes are written in camelCase — className instead of class, onClick instead of onclick, tabIndex instead of tabindex. This is because JSX transpiles to JavaScript, where hyphens in property names are not allowed.
| HTML | JSX | Reason |
|---|---|---|
class="wrapper" | className="wrapper" | class is a reserved word in JS |
onclick="handle()" | onClick={handle} | camelCase for JS properties |
style="color: red" | style={{ color: ‘red’ }} | Style object instead of string |
<input disabled> | <input disabled={true}> | Explicit boolean attributes |
Another important difference — self-closing tags. In HTML, some tags (br, hr, input) may be left unclosed. In JSX, all self-closing tags must have a closing slash: <br />, <input />. SVG attribute names are also converted to camelCase: strokeWidth, fillOpacity.
Browsers do not understand JSX directly. Before execution, JSX code goes through a transpiler — Babel, TypeScript or esbuild. Each JSX element is turned into a createElement or jsx/runtime call.
// Original JSX
const element = <h1 className="title">Hello</h1>;
// After transpilation
const element = React.createElement(
'h1',
{ className: 'title' },
'Hello'
);
With React 17, a new JSX transformation appeared that does not require importing React. Automatic import of jsx-runtime allows writing components without import React from ‘react’. Babel and TypeScript support this transformation via {"runtime": "automatic"} configuration.
Although JSX is associated with React, other frameworks also use it. SolidJS uses JSX with compilation into real DOM nodes, without Virtual DOM. Preact is a lightweight alternative to React with full JSX support. Vue supports JSX via @vue/babel-plugin-jsx, although its main template is template.
A key difference is expression semantics. In React, JSX expressions are executed on every render. In SolidJS, JSX compiles once and updates are tracked via signals. This affects performance: SolidJS does not require Virtual DOM and reconciliation, making JSX rendering faster.
In TypeScript, JSX is supported at the language level. Files with the .tsx extension automatically handle JSX syntax. Props typing is one of the main advantages of TypeScript + JSX: the IDE suggests expected attributes, callback types, and prop requirements.
Write JSX code that is easy to read and maintain. Extract complex expressions into separate variables or functions — this improves readability and allows testing logic separately from markup. Use fragments instead of unnecessary div wrappers.
The indentation rule — maintain indentation for nested elements. Each nesting level is one indentation level. The closing tag should be at the same level as the opening tag. For long attributes, use line breaks.
Avoid inline arrow functions in props if they are created on every render. In such cases, wrap the callback in useCallback or move the function outside the component. Split complex components into smaller ones — each component should handle one logical unit of the interface.
Frequently Asked Questions
Yes, through the Babel plugin @babel/plugin-transform-react-jsx, JSX can be configured for any library. SolidJS, Preact, Nerv and other frameworks use JSX with their own runtime. For full independence, you can set the pragma to your own function.
class is a reserved word in JavaScript. JSX transpiles to createElement, where the second argument passes a props object. The class property conflicts with ES6 class syntax, so React chose className.
Use template strings or the classnames library: className={`btn ${isActive ? ‘active’ : ‘’}`}. For complex logic, install the npm package clsx or classnames, which accept objects and arrays.
JSX only supports expressions, not statements. For conditions, use the ternary operator, logical AND (&&) or logical OR (||). For complex logic, extract the condition into a separate variable or function.
The key attribute helps React identify list elements during re-render. Without key, React re-renders the entire list on change. With a unique key, React reuses DOM nodes and reorders elements instead of recreating them.
Summary
We will develop a mobile application turnkey
IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.
Read also