JSX looks like HTML embedded in JavaScript, but it's actually syntactic sugar that a compiler, like Babel, transforms into plain JavaScript calls to React.createElement(), or an equivalent automatic runtime function in modern React, before the browser ever sees it — <h1>Hello!</h1> compiles down to something functionally equivalent to React.createElement('h1', null, 'Hello!'). Because it compiles to plain JavaScript, JSX lets you embed real JavaScript expressions directly inside curly braces, {expression}, mixing markup and logic together far more naturally than working with createElement() calls by hand.
1Understanding JSX
JSX looks like HTML embedded in JavaScript, but it's actually syntactic sugar that a compiler, like Babel, transforms into plain JavaScript calls to React.createElement(), or an equivalent automatic runtime function in modern React, before the browser ever sees it — <h1>Hello!</h1> compiles down to something functionally equivalent to React.createElement('h1', null, 'Hello!'). Because it compiles to plain JavaScript, JSX lets you embed real JavaScript expressions directly inside curly braces, {expression}, mixing markup and logic together far more naturally than working with createElement() calls by hand.
Since JSX ultimately compiles down to plain JavaScript function calls, anything you can do in JSX you could technically also write by hand with React.createElement() directly — JSX just makes it dramatically more readable.
const name = 'Ana';
const element = <h1>Hello, {name}!</h1>;
console.log(element.type, element.props.children);2Practical Example
Here is a real-world application of JSX showing how it is used in production React code.
function List() {
const items = ['Apples', 'Bananas', 'Cherries'];
return (
<ul>
{items.map(item => <li key={item}>{item}</li>)}
</ul>
);
}3Best Practices
Follow these guidelines when working with JSX:
1. Wrap JavaScript expressions you want to embed in JSX inside curly braces, like {user.name}, remembering that statements like if or for cannot go directly inside JSX this way
2. Use className instead of class, and camelCase for other attributes like onClick, since JSX attributes map to JavaScript/DOM property names, not raw HTML attribute names
3. Always return a single root element, or a Fragment, from a component, since JSX cannot return multiple sibling elements directly without one
Tip: Since JSX ultimately compiles down to plain JavaScript function calls, anything you can do in JSX you could technically also write by hand with React.createElement() directly — JSX just makes it dramatically more readable.
const name = 'Ana';
const element = <h1>Hello, {name}!</h1>;
console.log(element.type, element.props.children);4Attributes: className and style Objects
JSX attributes map to JavaScript/DOM property names, not raw HTML attribute strings. class becomes className, for becomes htmlFor, onclick becomes onClick, and style takes a JavaScript object of camelCased CSS properties instead of a semicolon-separated string.
<div
className="card"
style={{ backgroundColor: 'white', fontSize: 14 }}
onClick={handleClick}
>5Automatic Escaping Prevents Injection
Any value rendered through JSX's curly braces is escaped before being inserted into the DOM. A user-supplied string like <script>alert(1)</script> rendered as {comment.text} shows up as literal, harmless text on the page rather than being parsed as an actual tag — this is what makes JSX safe against XSS by default.
const comment = { text: '<script>alert(1)</script>' };
return <p>{comment.text}</p>;