JSX is the syntax that makes React code look the way it does — HTML-like tags sitting comfortably inside JavaScript files. It is the first thing that feels magical about React and, for many beginners, the first thing that produces confusing errors. This guide gives you the rules and the reasoning so JSX stops being mysterious.
JSX stands for JavaScript XML. It is not a template language and it is not a string; it is a thin syntax layer that a build tool (like the one bundled with Vite) compiles into ordinary JavaScript function calls before your code ever reaches the browser.
What JSX compiles into
When you write JSX, a compiler transforms it. This line:
const heading = <h1 className="title">Hello CodeBegun</h1>;
becomes roughly this plain JavaScript:
const heading = React.createElement(
"h1",
{ className: "title" },
"Hello CodeBegun"
);
You almost never write createElement by hand, but knowing that JSX is just JavaScript underneath explains every rule that follows. Attributes become object properties. Child elements become arguments. And because it compiles to a JavaScript expression, JSX can only ever produce one value — which is why a component must return a single root element. If you are still fuzzy on how components fit together, review what React is first.
Embedding JavaScript with curly braces
The single most-used JSX feature is { }. Inside curly braces you can put any JavaScript expression — a variable, a math operation, a function call, a ternary:
function Profile() {
const name = "Praneeth";
const scores = [8, 9, 10];
const average = scores.reduce((a, b) => a + b, 0) / scores.length;
return (
<div>
<p>Student: {name}</p>
<p>Average score: {average.toFixed(1)}</p>
<p>Status: {average >= 8 ? "On track" : "Needs practice"}</p>
</div>
);
}
export default Profile;
The key word is expression. An expression produces a value. A statement (like a full if block or a for loop) does not, so it cannot go inside curly braces. This one distinction explains most "why won't my JSX work" questions.
Common mistake: Writing
{if (x) { ... }}inside JSX. It fails becauseifis a statement, not an expression. Use a ternary{x ? a : b}for inline choices, or compute the value above thereturnand just drop the variable in.
Attributes use camelCase
HTML attributes carry over to JSX with two important adjustments. First, most multi-word attributes become camelCase: onclick becomes onClick, tabindex becomes tabIndex. Second, two attributes are renamed outright because their HTML names are reserved JavaScript words:
| HTML | JSX |
|---|---|
class |
className |
for |
htmlFor |
onclick |
onClick |
tabindex |
tabIndex |
You pass values with quotes for strings and curly braces for JavaScript:
<img src={logoUrl} alt="CodeBegun logo" className="brand-logo" />
Note that self-closing tags must close with />. In HTML you can get away with a bare <img> or <br>; in JSX the slash is mandatory or you get a compile error.
Returning one parent element
Because JSX compiles to a single expression, a component can return only one root node. This is invalid:
// ❌ Two siblings with no wrapper — syntax error
return (
<h2>Title</h2>
<p>Body</p>
);
You have two fixes. Wrap the elements in a container like a <div>, or — when you do not want an extra DOM node — use a Fragment, written as empty tags:
function Card() {
return (
<>
<h2>React Track</h2>
<p>Components, hooks, and routing.</p>
</>
);
}
export default Card;
The <>...</> Fragment groups the siblings without adding a wrapper div to the actual page. This keeps your HTML clean, which matters for styling and accessibility.
Conditional rendering
Since you cannot use if inside JSX, you render conditionally with expressions. There are three idiomatic patterns.
The ternary for either/or:
{isLoggedIn ? <Dashboard /> : <LoginButton />}
The logical && for show-or-nothing:
{cartItems.length > 0 && <Badge count={cartItems.length} />}
And computing ahead of the return for anything complex:
function Status({ score }) {
let label;
if (score >= 9) label = "Excellent";
else if (score >= 7) label = "Good";
else label = "Keep practicing";
return <span>{label}</span>;
}
Pro tip: With
&&, be careful using a number as the left side.{count && <Badge />}will literally render0on screen when count is zero, because0is falsy but still a renderable value. Convert to a real boolean with{count > 0 && <Badge />}.
Rendering lists
You render collections by mapping an array to JSX elements. Every element in the list needs a key — a stable, unique identifier that helps React track items across re-renders:
function StudentList() {
const students = [
{ id: 101, name: "Raju" },
{ id: 102, name: "Jaswanth" },
{ id: 103, name: "Narasimha" },
];
return (
<ul>
{students.map((s) => (
<li key={s.id}>{s.name}</li>
))}
</ul>
);
}
export default StudentList;
Use a real unique id from your data as the key whenever possible. Using the array index as a key is a common shortcut that causes subtle bugs when items are added, removed, or reordered, because the index of an item changes even though the item itself did not.
Interview note: "Why do lists need keys in React?" is one of the most common React interview questions. The complete answer: keys give each item a stable identity so React's diffing can match old and new elements correctly, updating only what changed. Then add the warning about not using array indices for dynamic lists. This and related questions are collected in the React interview questions guide.
Styling in JSX
Inline styles in JSX are objects, not strings, and their property names are camelCase:
const boxStyle = { backgroundColor: "#0f172a", padding: "12px" };
<div style={boxStyle}>Highlighted</div>
Notice the double braces when written inline: style={{ ... }}. The outer braces enter JavaScript; the inner braces are the object literal. Most real projects, however, use CSS classes via className or a CSS framework rather than heavy inline styles.
What renders and what does not
JSX has clear rules about which values actually appear on screen when you drop them in curly braces. Strings and numbers render as-is. But four values render nothing: false, null, undefined, and true. This is deliberate and it is what makes the && conditional pattern work — when the left side is false, React renders nothing rather than the word "false".
function Notice({ message }) {
return (
<div>
{message} {/* renders the string */}
{null} {/* renders nothing */}
{false} {/* renders nothing */}
{[1, 2, 3]} {/* renders 123 — arrays are flattened */}
</div>
);
}
Arrays are flattened and each item rendered in order, which is exactly why .map() works for lists. Objects, however, cannot be rendered directly — {someObject} throws the classic "Objects are not valid as a React child" error. When you hit that error, you are almost always trying to render an object where you meant to render one of its properties.
Spreading props
When you already have an object of properties, you can spread it onto an element instead of writing each attribute by hand. This mirrors the spread operator from plain JavaScript:
const inputProps = { type: "text", placeholder: "Name", maxLength: 40 };
<input {...inputProps} />
This is handy for passing a bundle of props through a wrapper component, but use it thoughtfully — spreading unknown props onto a DOM element can leak invalid attributes. It is a tool worth knowing and applying deliberately, not everywhere.
Comments and whitespace
Comments inside JSX go in curly braces as JavaScript comments: {/* like this */}. Regular <!-- HTML comments --> do not work. JSX also collapses whitespace much like HTML, so you control spacing with layout and CSS rather than by adding spaces in the markup.
Putting it together
JSX is small once you internalize four rules: everything dynamic goes in { } expressions, attributes are camelCase (with className and htmlFor renamed), a component returns exactly one root (use a Fragment for siblings), and lists need stable keys. Master those and you can read and write the vast majority of React code you will meet.
The next building block is making components respond to change. State and the hooks that manage it are covered in the React hooks introduction, and when you start capturing user input you will apply JSX rules directly in controlled form components. To see JSX used across a complete first app, work through the beginner React tutorial. The best way to lock this in is to open a Vite project and rewrite each example above from memory until the syntax feels automatic.
Frequently Asked Questions
Is JSX required to use React?
Why is it className instead of class in JSX?
Can I write if statements inside JSX?
Why does React need a key when rendering a list?
What does it mean that JSX must have one parent element?
Want to Build Your Career in Java Full Stack with AI?
Join CodeBegun and train with working industry engineers — Explore the Program

