JSX
JSX lets you write HTML-like tags directly inside JavaScript. It is the reason React code is easy to read: you can see the shape of the page right next to the logic that fills it with data.
In this lesson you will learn what JSX really is, the few rules that make it different from HTML, how to put JavaScript values inside it with curly braces, and what the browser finally receives after JSX is compiled.
JSX is JavaScript in disguise
JSX stands for JavaScript XML. It is a syntax extension: browsers do not understand it, so a tool (Vite in your project, or this site's editor) compiles it to normal JavaScript function calls before the code runs.
const heading = <h1 className="title">Namaste, Aarav</h1>;After compiling, the line above becomes roughly this:
import { jsx } from "react/jsx-runtime";
const heading = jsx("h1", { className: "title", children: "Namaste, Aarav" });The jsx() call returns a plain JavaScript object that describes an <h1> element. It does not create a real DOM element. React reads these description objects later and builds or updates the real page. You can prove that JSX is just an object:
const heading = <h1 className="title">Namaste, Aarav</h1>;
console.log(typeof heading);
console.log(heading.type);
console.log(JSON.stringify(heading.props));object
h1
{"className":"title","children":"Namaste, Aarav"}Because JSX produces values, you can store it in variables, return it from functions, put it in arrays and pass it to other functions, exactly like any other value.
Curly braces: JavaScript inside JSX
Inside JSX, curly braces { } open a window back into JavaScript. Anything that produces a value can go there: a variable, a calculation, a function call or a ternary. You can use braces for the text between tags and for attribute values.
import { createRoot } from "react-dom/client";
const student = {
name: "Isha Verma",
rollNo: 42,
city: "Lucknow",
marks: [78, 91, 85],
photo: "https://course.ethicscomputer.in/assets/samples/avatar.svg",
};
function IdCard() {
const total = student.marks.reduce((sum, m) => sum + m, 0);
const average = Math.round(total / student.marks.length);
return (
<div className="card">
<img src={student.photo} alt={`Photo of ${student.name}`} width="80" />
<h2>{student.name.toUpperCase()}</h2>
<p>Roll number: {student.rollNo}, {student.city}</p>
<p>Average marks: {average} ({average >= 80 ? "Distinction" : "Pass"})</p>
</div>
);
}
createRoot(document.getElementById("root")).render(<IdCard />);Notice the attribute src={student.photo}: no quotes around the braces. Use quotes for fixed text (width="80") and braces for JavaScript values. A template literal inside braces builds the alt text from data.
Braces accept expressions, not statements. You cannot write if, for or const inside them. Use a ternary (a ? b : c) or compute the value above the return, as average is computed here. You will learn more patterns in Conditional Rendering.
The rules that differ from HTML
JSX is stricter than HTML and uses JavaScript naming in a few places:
- Return one root element. A component returns one value, so wrap sibling elements in a parent. If you do not want an extra
<div>on the page, use a fragment:<>and</>. - Close every tag. Empty elements need a slash:
<img />,<br />,<input />. - Use camelCase attribute names.
classbecomesclassName(becauseclassis a JavaScript keyword),forbecomeshtmlFor,tabindexbecomestabIndex, and events areonClick,onChangeand so on. Attributes starting witharia-anddata-keep their dashes. styletakes an object, not a string. Writestyle={{ color: "teal", fontSize: 18 }}. The outer braces open JavaScript; the inner braces are the object. CSS property names are camelCase, and plain numbers mean pixels for most properties.- Comments go inside braces:
{/* like this */}.
Here is a small HTML form converted to JSX with all these rules applied:
import { createRoot } from "react-dom/client";
function Subscribe() {
return (
<>
{/* A fragment: no extra div is added to the page */}
<h2 style={{ color: "#087ea4", marginBottom: 4 }}>Train alerts</h2>
<p>Get platform changes for the Jaipur Express.</p>
<label htmlFor="phone">Mobile number</label>
<br />
<input id="phone" type="tel" placeholder="98765 43210" aria-describedby="hint" />
<p id="hint" className="hint">We send one SMS per journey.</p>
</>
);
}
createRoot(document.getElementById("root")).render(<Subscribe />);What JSX shows and what it ignores
Strings and numbers between tags appear as text. The values true, false, null and undefined render nothing, which is handy for showing something only sometimes. Arrays of elements render one after another. A plain object, however, is not valid as a child, and React throws an error if you try to render one.
import { createRoot } from "react-dom/client";
const order = { item: "Masala dosa", qty: 2 };
function Demo() {
return (
<ul>
<li>Number: {42}</li>
<li>Boolean: {true} (nothing shown)</li>
<li>Null: {null} (nothing shown)</li>
<li>Zero: {0} (zero is shown!)</li>
<li>Object field: {order.item} x {order.qty}</li>
{/* <li>{order}</li> would throw: objects are not valid as a React child */}
</ul>
);
}
createRoot(document.getElementById("root")).render(<Demo />);JSX also escapes every value you put in braces. If a user types <script> into a comment box and you render {comment}, React shows the characters as text instead of running them. This protects your app from cross-site scripting (XSS) attacks. React has an escape hatch named dangerouslySetInnerHTML for inserting raw HTML; as the name says, avoid it unless the HTML comes from a source you fully trust.
Common mistakes
- Writing
classinstead ofclassName. It is a common habit from HTML; React warns about it in development. - Two root elements.
return <h1>Hi</h1><p>Bye</p>;is a syntax error. Wrap them in<>...</>. - Quotes around braces.
src="{photo}"passes the literal text{photo}. Writesrc={photo}. - A style string.
style="color: red"fails; writestyle={{ color: "red" }}. - Showing
0by accident.{count && <p>...</p>}prints0whencountis zero, because0is a number and numbers render.
Key points
- JSX is a syntax extension that compiles to
jsx()calls returning plain description objects. - Curly braces put any JavaScript expression into JSX, in text or in attributes.
- Return a single root element; use a fragment
<>...</>to avoid extra wrappers. - Use
className,htmlFor, camelCase events and astyleobject. true,false,nullandundefinedrender nothing;0and other numbers render.- React escapes values in braces, which protects against XSS.
Exercise
Write a component TrainTicket that stores a passenger name, train name, from and to cities, coach and seat in an object. Render them in JSX with a heading for the train, a line "From Rohtak to Jaipur", and the seat as "Coach B2, Seat 34". Give the outer element a CSS class ticket and a light border using a style object.
Show solution
import { createRoot } from "react-dom/client";
const ticket = { passenger: "Kabir Singh", train: "Intercity Express", from: "Rohtak", to: "Jaipur", coach: "B2", seat: 34 };
function TrainTicket() {
return (
<div className="ticket" style={{ border: "1px solid #ccc", padding: 12, borderRadius: 8 }}>
<h2>{ticket.train}</h2>
<p>Passenger: {ticket.passenger}</p>
<p>From {ticket.from} to {ticket.to}</p>
<p>Coach {ticket.coach}, Seat {ticket.seat}</p>
</div>
);
}
createRoot(document.getElementById("root")).render(<TrainTicket />);Every value comes from the object through curly braces, the class uses className, and the style attribute receives an object with camelCase property names.
Quick Quiz
1. What does a JSX element such as <h1>Hi</h1> produce when the code runs?
JSX compiles to jsx() calls that return description objects; React creates real DOM later.
2. Which line is valid JSX?
JSX uses htmlFor and a style object, and empty elements such as img must be closed with />.
3. What does {false} render inside JSX?
true, false, null and undefined render nothing, which is useful for conditional content.
4. Why must return <h1>A</h1><p>B</p>; be changed?
JSX expressions need one root; <>...</> groups siblings without adding a DOM element.
Learn React with a mentor
Free lessons get you started. Our Full Stack Web Development training adds real projects and code reviews from working developers.
- Project-based learning
- Mentor code reviews
- Free counselling call
