😵 The Problem
You open a React component for the first time and see this:
function App() {
return (
<div>
<h1>Hello World</h1>
<p>Welcome to my app</p>
</div>
);
}
And you're probably thinking:
“Wait… isn't this HTML inside JavaScript?” 😅
Technically, it looks like HTML.
But it isn't.
This syntax is called JSX, and it's one of the things that makes React feel so different from traditional JavaScript development.
The confusing part is that JSX looks simple on the surface.
But once you start using JavaScript expressions, conditions, components, lists, events, and dynamic UI inside it, you'll quickly realize there's a bit more going on.
💡 The Solution: JSX
JSX lets you describe what your UI should look like using a syntax that feels similar to HTML.
For example:
function Welcome() {
const name = "John";
return (
<div>
<h1>Hello {name}</h1>
<p>Welcome back!</p>
</div>
);
}
The interesting part is this:
{name}
Anything inside {} can contain a JavaScript expression.
That's where JSX starts becoming really useful.
🧠 JSX Isn't HTML
This is probably the first thing worth remembering.
JSX:
<h1 className="title">Hello</h1>
isn't directly sent to the browser as HTML.
Your build tool transforms JSX into JavaScript that React can work with.
Conceptually, something like:
<h1>Hello</h1>
becomes something similar to:
React.createElement("h1", null, "Hello");
Modern React tooling may use the automatic JSX transform, so you don't necessarily write or import React for JSX anymore.
The important idea is:
JSX is a syntax layer that helps you describe UI in JavaScript.
🔥 The Real Power: JavaScript Inside JSX
This is where JSX becomes much more interesting.
You can calculate values:
function Product({ price, quantity }) {
return (
<p>
Total: ${price * quantity}
</p>
);
}
You can call functions:
function App() {
const getGreeting = () => "Welcome back";
return <h1>{getGreeting()}</h1>;
}
You can use ternary expressions:
function UserStatus({ isLoggedIn }) {
return (
<h2>
{isLoggedIn ? "Welcome back!" : "Please log in"}
</h2>
);
}
And you can render arrays:
const users = ["John", "Jane", "Alex"];
function UserList() {
return (
<ul>
{users.map(user => (
<li key={user}>{user}</li>
))}
</ul>
);
}
This is the big advantage.
Your UI and the JavaScript controlling that UI stay close together.
🚨 But JSX Has Rules
This is where beginners usually start getting confused.
1. You Need One Parent
This won't work:
return (
<h1>Hello</h1>
<p>Welcome</p>
);
JSX expects one root element.
You can wrap them:
return (
<div>
<h1>Hello</h1>
<p>Welcome</p>
</div>
);
But adding unnecessary <div> elements everywhere isn't great either.
That's where fragments help:
return (
<>
<h1>Hello</h1>
<p>Welcome</p>
</>
);
Much cleaner.
🎯 JSX Uses className, Not class
This catches almost everyone coming from HTML.
HTML:
<div class="card"></div>
JSX:
<div className="card"></div>
Why?
Because JSX follows JavaScript-style property naming in many places.
You'll also see:
<label htmlFor="email">Email</label>
instead of:
<label for="email">Email</label>
Small difference.
But you'll write these constantly.
🔥 Dynamic Attributes
JSX becomes really useful when attributes need to change.
Instead of:
<img src="profile.jpg" />
You can do:
const imageUrl = "/images/profile.jpg";
<img src={imageUrl} alt="Profile" />
Or:
const isDisabled = true;
<button disabled={isDisabled}>
Save
</button>
The {} tells JSX:
“I'm switching back to JavaScript now.”
That's probably the easiest way to mentally understand JSX.
🧩 JSX + Components
This is where JSX really starts to shine.
You can use your own components almost like HTML elements:
function Button({ children }) {
return <button>{children}</button>;
}
function App() {
return (
<div>
<Button>Login</Button>
<Button>Register</Button>
</div>
);
}
Notice the difference:
<button>
is a normal HTML element.
<Button>
is a React component.
And yes, the capital letter matters.
💡 Real Developer Insight
Here's something you'll appreciate once your React apps get bigger:
Don't turn JSX into a giant JavaScript playground.
This is technically possible:
return (
<div>
{users
.filter(user => user.active)
.sort((a, b) => a.name.localeCompare(b.name))
.map(user => (
<Card key={user.id} user={user} />
))}
</div>
);
It works.
But imagine another developer opening this six months later. 😅
A better approach is often:
const activeUsers = users
.filter(user => user.active)
.sort((a, b) => a.name.localeCompare(b.name));
return (
<div>
{activeUsers.map(user => (
<Card key={user.id} user={user} />
))}
</div>
);
Same result.
Much easier to reason about.
My rule is pretty simple:
JSX should describe the UI, not become the place where all your business logic lives.
⚠️ Common Developer Mistakes
1. Writing class Instead of className
<div class="container">
❌ Not the JSX way.
Use:
<div className="container">
2. Putting Statements Inside {}
This doesn't work:
{
if (isLoggedIn) {
return <Dashboard />;
}
}
JSX expects an expression there.
Use a ternary:
{isLoggedIn ? <Dashboard /> : <Login />}
Or move the logic outside the JSX.
3. Forgetting key When Rendering Lists
{users.map(user => (
<div>{user.name}</div>
))}
React needs a stable key:
{users.map(user => (
<div key={user.id}>{user.name}</div>
))}
And don't blindly use the array index as the key when items can be reordered, inserted, or removed.
4. Making JSX Too Clever
This:
<div>
{condition && data?.items?.filter(...).map(...)}
</div>
might save a few lines.
But if the expression keeps growing, move the logic somewhere easier to understand.
Readable code wins.
🚀 Best Practice Summary
{} whenever you need a JavaScript expression inside JSX
0 Comments