JSX Syntax
Table of Contents + −
In the last lesson, Introduction to JSX, you saw that JSX lets you write HTML-looking code right inside JavaScript. Now here is the catch:
- JSX looks like HTML, but it is not HTML. It has a few strict rules of its own.
- Break even one of them and the whole component refuses to render. You get a red error screen instead.
So this lesson is your rulebook. Once these rules click, JSX stops causing errors and starts feeling natural.
🤔 Why JSX Has Its Own Rules
Here is the pain you hit:
- You copy some HTML into your React component, hit save, and the app breaks.
- The error message talks about “adjacent JSX elements” or “unknown prop class”, right? And you have no idea what it means.
The reason is simple:
- JSX is not really HTML. It is really JavaScript that is written to look like HTML.
- Every JSX tag you write gets turned into a JavaScript function call in the background.
- JavaScript is much stricter than a browser, so it will not quietly forgive small mistakes the way HTML does.
The fix is to learn the handful of rules that JSX enforces. Learn these and most of your “why won’t this render” problems go away.
🧩 Rule 1: Return One Single Root Element
A component must return one parent element. Just one. Think of it like a moving box: you can put many things inside the box, but you can only hand someone one box at a time, not three loose items in your arms.
Here is the wrong way and the right way, side by side.
function Profile() { // ❌ Avoid: two elements sitting next to each other with no parent return ( <h1>Riya</h1> <p>Frontend developer</p> );}
// ✅ Good: wrap them in one parent <div>function Profile() { return ( <div> <h1>Riya</h1> <p>Frontend developer</p> </div> );}Here is what each version is doing:
- In the wrong version,
<h1>and<p>are returned next to each other with nothing wrapping them. JSX cannot return two things at once, so it errors out. - In the fixed version, both sit inside a single
<div>. Now the component returns one element, and that one element holds two children. That is allowed.
So why does this rule exist? Because each return in JavaScript can only hand back one value. A component returns one JSX element, and that one element can hold as many children as you like.
🧩 Rule 2: Use a Fragment When You Do Not Want an Extra Div
Sometimes you do not want a wrapper <div> cluttering up your page. Here is why:
- Wrapping everything in extra
<div>tags makes the final HTML messy. - It can also break some CSS layouts.
React gives you a clean way out, called a Fragment. A Fragment is an empty tag, <> and </>, that groups elements without adding any real element to the page.
function Profile() { // ✅ Good: a Fragment groups the elements but adds nothing to the page return ( <> <h1>Riya</h1> <p>Frontend developer</p> </> );}Here is what the Fragment does:
- The
<>opens the Fragment and the</>closes it, with both children inside, so the one-root-element rule is still satisfied. - When this renders, no extra wrapper shows up in the page. You just get the
<h1>and the<p>.
Tip
Reach for a Fragment when you only need to group elements and a real wrapper would get in the way. Reach for a <div> when you actually want a container you can style or target with CSS.
🧩 Rule 3: Close Every Tag
In HTML you can get away with leaving some tags open and the browser forgives you. JSX does not. Every single tag must be closed.
This matters most for tags that have no children, like an image or a line break:
- In HTML you might write
<img>or<br>and move on. - In JSX you must add a slash before the closing bracket. This makes them self-closing.
function Banner() { return ( <div> {/* ❌ Avoid: open tags that are never closed */} {/* <img src="logo.png"> */} {/* <br> */}
{/* ✅ Good: self-closing with a slash */} <img src="logo.png" alt="Company logo" /> <br /> </div> );}Here is what the slash is telling JSX:
- See the
/right before the>? That says the tag opens and closes itself in one go, so<img />and<br />carry no children and finish themselves. - Tags that do have children still need a proper closing tag, like
<p>Hello</p>. Either way, nothing is ever left hanging open.
Caution
Forgetting the slash on a self-closing tag is one of the most common JSX errors. If your build complains about an “unterminated” or “expected corresponding closing tag” message, check your <img>, <br>, and <input> tags first.
🧩 Rule 4: Use className, Not class
Now this one trips up almost everyone coming from HTML. In plain HTML you give an element a CSS class with the class attribute. In JSX you cannot use class. You have to write className instead.
function Card() { return ( // ❌ Avoid: class is a reserved word in JavaScript // <div class="card">Hello</div>
// ✅ Good: use className <div className="card">Hello</div> );}So why this swap?
- The word
classis already reserved in JavaScript. It is used to create classes in code. - Since JSX is really JavaScript, the word
classis taken, so React renames it toclassName. - When the page renders, React turns
className="card"back into a normalclass="card"in the actual HTML, so your CSS still works exactly as expected.
One more like this: the HTML for attribute on a label also clashes with the JavaScript for loop. So in JSX you write htmlFor instead.
🧩 Rule 5: Write Attributes in camelCase
Most JSX attributes are written in camelCase. Here is what that means:
- The first word is lowercase and every word after it starts with a capital letter, with no spaces or dashes.
- So
onclickbecomesonClick, andtabindexbecomestabIndex.
function SaveButton() { return ( // ❌ Avoid: lowercase HTML-style event and attribute names // <button onclick={save} tabindex="0">Save</button>
// ✅ Good: camelCase <button onClick={save} tabIndex={0}> Save </button> );}Look at onClick with the capital C, and tabIndex with the capital I. HTML does not care about capitalization. JSX does, because these names map to real JavaScript property names that are written in camelCase.
This table shows the common ones people get wrong.
| HTML way | JSX way |
|---|---|
| class | className |
| for | htmlFor |
| onclick | onClick |
| tabindex | tabIndex |
| maxlength | maxLength |
Note
A few attributes keep their plain lowercase names. They are not standard HTML attributes turned into properties. The two you will meet most are aria-label and data-id, which stay with their dashes. Everything else, treat as camelCase.
🧩 Rule 6: Nest Tags Properly
Tags have to be closed in the reverse order you opened them:
- If you open
<div>then<p>, you must close<p>first, then<div>. - You cannot cross them over.
function Message() { return ( // ❌ Avoid: tags crossed over each other // <div><p>Hello</div></p>
// ✅ Good: inner tag closes before the outer one <div> <p>Hello</p> </div> );}Think of it like nesting boxes. You put the small box inside the big box. To take the small box out, you open the big box first, then reach the small one. You cannot pull the small box out through the side of the big box. Tags work the same way: the one you opened last is the one you close first.
⚠️ Common Mistakes
A quick run through the slips that catch people most often.
- Returning two elements with no parent. Wrap them in a
<div>or a Fragment<>. - Leaving a tag open. Every tag closes, and tags with no children self-close with a slash like
<img />. - Writing
classinstead ofclassName. The wordclassis reserved in JavaScript. - Using lowercase event names like
onclick. JSX wants camelCase, soonClick. - Crossing your tags so they overlap. Close the inner tag before the outer one.
✅ Best Practices
Some small habits that keep JSX smooth.
- Reach for a Fragment
<>instead of an extra<div>when you only need to group things, so your page stays clean. - Always add
alttext to your<img />tags. It helps screen readers and shows useful text if the image fails to load. - Let your editor close tags for you. Most editors auto-close JSX tags and warn you when something is wrong. That catches these mistakes before you even save.
- When the error mentions “adjacent JSX elements”, go straight to your
returnand check that everything sits inside one parent.
🧩 What You’ve Learned
A quick recap of the rules that keep your JSX from breaking.
- ✅ A component must return one single root element, either a real element like
<div>or a Fragment<>. - ✅ A Fragment groups elements without adding an extra wrapper to the page.
- ✅ Every tag must be closed, and childless tags self-close with a slash like
<br />. - ✅ Use
classNameinstead ofclass, andhtmlForinstead offor. - ✅ Most attributes are camelCase, so
onClickandtabIndex, notonclickandtabindex. - ✅ Nest tags properly, closing the inner tag before the outer one.
Check Your Knowledge
Test what you learned. Pick an answer for each question, then click Check.
- 1
What happens if a component tries to return two elements that are not wrapped in a parent?
Why: JSX can only return one root element, so two unwrapped elements cause an error. Wrap them in a div or a Fragment.
- 2
Why must you write className instead of class in JSX?
Why: Since class is already reserved in JavaScript, JSX uses className, which React converts back to class in the real HTML.
- 3
Which of these is the correct way to write a self-closing image tag in JSX?
Why: Childless tags must self-close with a slash before the closing bracket, like <img src="logo.png" />.
- 4
How should the HTML attribute onclick be written in JSX?
Why: Most JSX attributes use camelCase, so onclick becomes onClick with a capital C.
🚀 What’s Next?
Now that your JSX is built on solid rules, the next step is making it dynamic. You drop real JavaScript values straight into your markup.