JSX & Components — ReactJS Series Part 2

Learn how JSX works under the hood, how to create and nest React components, and the rules that make JSX different from HTML.

12 min read
0 views
By Siraj AL Zahran
ReactJavaScriptFrontendBeginnerJSXComponents
JSX & Components — ReactJS Series Part 2

Introduction

In Part 1, we learned that React is a JavaScript library for building UIs using components — small, reusable pieces that describe what the screen should look like. We also saw some code that looked like HTML sitting right inside JavaScript.

That "HTML-like" syntax is called JSX, and it's one of the first things that surprises new React developers. It's not HTML. It's not a template language. It's JavaScript in disguise.

In this part, we'll break down exactly how JSX works, learn its rules, and build properly structured React components from scratch.


What is JSX?

JSX stands for JavaScript XML. It's a syntax extension that lets you write HTML-like code inside JavaScript files.

javascript
1
2
3
function Greeting() {
return <h1>Hello, World!</h1>;
}

This looks like HTML, but it's actually syntactic sugar for a JavaScript function call. Behind the scenes, the JSX compiler (Babel) transforms it into:

javascript
1
2
3
function Greeting() {
return React.createElement("h1", null, "Hello, World!");
}

React.createElement creates a plain JavaScript object — a React element — that describes what should appear on screen. React reads these objects and uses them to build and update the DOM.

Why Not Just Use createElement Directly?

You can, but it gets unreadable fast:

javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// JSX version — clean and readable
function Card() {
return (
<div className="card">
<h2>Title</h2>
<p>Description</p>
</div>
);
}
 
// createElement version — same result, much harder to read
function Card() {
return React.createElement(
"div",
{ className: "card" },
React.createElement("h2", null, "Title"),
React.createElement("p", null, "Description")
);
}

JSX exists to make your code readable. It compiles down to createElement calls anyway, so there's no performance difference.


JSX Rules You Must Know

JSX looks like HTML, but it has its own rules. Breaking these rules causes errors, so let's go through each one.

1. Return a Single Root Element

A component must return one root element. This won't work:

javascript
1
2
3
4
5
6
7
// ❌ Error: Adjacent JSX elements must be wrapped
function Broken() {
return (
<h1>Title</h1>
<p>Text</p>
);
}

Fix it by wrapping in a <div> or a Fragment (<>...</>):

javascript
1
2
3
4
5
6
7
8
9
// ✅ Using a Fragment (no extra DOM element)
function Fixed() {
return (
<>
<h1>Title</h1>
<p>Text</p>
</>
);
}

Fragments (<>...</>) let you group elements without adding an extra <div> to the DOM.

2. Close All Tags

In HTML, some tags are self-closing (<img>, <br>, <input>). In JSX, every tag must be explicitly closed:

javascript
1
2
3
4
5
6
7
8
9
// ❌ Error in JSX
<img src="photo.jpg">
<br>
<input type="text">
 
// ✅ Correct in JSX
<img src="photo.jpg" />
<br />
<input type="text" />

3. Use className Instead of class

Since class is a reserved word in JavaScript, JSX uses className:

javascript
1
2
3
4
5
// ❌ Wrong
<div class="container">
 
// ✅ Correct
<div className="container">

4. Use htmlFor Instead of for

Similarly, for is reserved, so labels use htmlFor:

javascript
1
2
<label htmlFor="email">Email</label>
<input id="email" type="email" />

5. CamelCase for Event Handlers and Attributes

HTML uses lowercase (onclick, tabindex). JSX uses camelCase (onClick, tabIndex):

javascript
1
2
3
4
5
// HTML
<button onclick="handleClick()">Click</button>
 
// JSX
<button onClick={handleClick}>Click</button>

6. Use Curly Braces {} for JavaScript Expressions

Curly braces let you embed any JavaScript expression inside JSX:

javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
const name = "Siraj";
const age = 25;
 
function Profile() {
return (
<div>
<h1>{name}</h1>
<p>Age: {age}</p>
<p>Next year: {age + 1}</p>
<p>Uppercase: {name.toUpperCase()}</p>
</div>
);
}

You can put variables, math, function calls, ternary operators — any expression that produces a value. But you cannot put statements like if/else or for loops directly inside {}.


Expressions vs Statements in JSX

This distinction trips up many beginners:

javascript
1
2
3
4
5
// ✅ Expression — produces a value, works in JSX
{isLoggedIn ? "Welcome back!" : "Please log in"}
 
// ❌ Statement — doesn't produce a value, doesn't work in JSX
{if (isLoggedIn) { return "Welcome" }}

For conditional rendering, use ternaries or logical AND:

javascript
1
2
3
4
5
// Ternary — show one thing or another
{isLoggedIn ? <Dashboard /> : <LoginForm />}
 
// Logical AND — show or hide
{hasNotifications && <Badge count={3} />}

Building Components

A React component is a JavaScript function that returns JSX. There are a few conventions to follow.

Component Names Must Be Capitalized

React uses capitalization to distinguish between HTML elements and components:

javascript
1
2
3
4
5
6
7
// Lowercase → HTML element
<div> // renders a <div>
<span> // renders a <span>
 
// Uppercase → React component
<Header /> // renders your Header component
<UserCard /> // renders your UserCard component

If you name a component header (lowercase), React will try to render an HTML <header> tag instead of your component.

Function Components

The modern way to write React components is as functions:

javascript
1
2
3
4
5
6
7
8
function Welcome() {
return <h1>Welcome to React!</h1>;
}
 
// Arrow function variant — same thing
const Welcome = () => {
return <h1>Welcome to React!</h1>;
};

Both are identical. Use whichever style your team prefers.

Nesting Components

Components can render other components. This is how you build complex UIs from simple pieces:

javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function Header() {
return (
<header>
<Logo />
<Navigation />
</header>
);
}
 
function Logo() {
return <h1>MyApp</h1>;
}
 
function Navigation() {
return (
<nav>
<a href="/">Home</a>
<a href="/about">About</a>
</nav>
);
}

Header doesn't need to know how Logo or Navigation work internally. It just uses them. This separation of concerns is what makes React scalable.


Putting It Together: A Profile Card

Let's build a real component that uses everything we've learned. This interactive example renders a profile card with dynamic data, conditional rendering, and nested components:

Preview

What this demonstrates:

  • Nested componentsProfileCard uses Avatar, StatusBadge, Stat, and SkillTag
  • Dynamic data — Everything renders from the user object using {}
  • Conditional renderingStatusBadge shows green or gray based on isOnline
  • List renderinguser.skills.map() renders a SkillTag for each skill
  • The key prop — When rendering lists, each item needs a unique key so React can track them

Rendering Lists with .map()

One of the most common patterns in React is rendering a list of items. You use JavaScript's .map() method:

javascript
1
2
3
4
5
6
7
8
9
10
11
const fruits = ["Apple", "Banana", "Cherry"];
 
function FruitList() {
return (
<ul>
{fruits.map((fruit) => (
<li key={fruit}>{fruit}</li>
))}
</ul>
);
}

Why Do We Need key?

The key prop helps React identify which items changed, were added, or removed. Without keys, React has to re-render the entire list every time. With keys, it only updates what changed.

Rules for keys:

  • Must be unique among siblings (not globally)
  • Must be stable — don't use array indexes if the list can reorder
  • Should come from your data (IDs, slugs, etc.)
javascript
1
2
3
4
5
// ✅ Good — stable, unique ID
{users.map((user) => <UserCard key={user.id} user={user} />)}
 
// ⚠️ Avoid — index changes when items reorder
{users.map((user, index) => <UserCard key={index} user={user} />)}

Inline Styles in JSX

In HTML, you write style="color: red; font-size: 14px". In JSX, style takes a JavaScript object with camelCase properties:

javascript
1
2
3
4
5
// HTML
<div style="background-color: #0F0D0B; font-size: 16px;">
 
// JSX
<div style={{ backgroundColor: "#0F0D0B", fontSize: "16px" }}>

The double curly braces look odd at first: the outer {} says "JavaScript expression incoming", and the inner {} is the object literal.

Note: In real projects, you'll usually use CSS classes (via className) or a CSS-in-JS solution like Tailwind instead of inline styles. Inline styles are fine for quick prototypes or truly dynamic values.


Common Mistakes

1. Forgetting Curly Braces

javascript
1
2
3
4
5
// ❌ Renders the literal text "user.name"
<h1>user.name</h1>
 
// ✅ Renders the value of user.name
<h1>{user.name}</h1>

2. Using class Instead of className

javascript
1
2
3
4
5
// ❌ Warning in console
<div class="box">
 
// ✅ Correct
<div className="box">

3. Returning Multiple Root Elements

javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
// ❌ Syntax error
return (
<h1>Title</h1>
<p>Text</p>
);
 
// ✅ Wrap in Fragment
return (
<>
<h1>Title</h1>
<p>Text</p>
</>
);

4. Forgetting key in Lists

React will warn you in the console. Always add a key when using .map() to render elements.


JSX is Just JavaScript

This is the most important takeaway: JSX is not a separate language. It's JavaScript with a convenient syntax for describing UI. Everything compiles to React.createElement calls, which produce plain objects.

This means you can:

  • Store JSX in variables: const header = <h1>Hello</h1>;
  • Return JSX from functions (that's what components are)
  • Pass JSX as arguments (we'll see this with props in Part 3)
  • Put JSX in arrays, ternaries, and any other JavaScript structure

What's Next?

In this article, we covered:

  • ✔ What JSX is and how it compiles to createElement
  • ✔ JSX rules (single root, close tags, className, camelCase)
  • ✔ How to embed JavaScript expressions with {}
  • ✔ Building and nesting components
  • ✔ Rendering lists with .map() and the key prop
  • ✔ Inline styles in JSX

In Part 3: Props, we'll learn how to pass data between components — from parent to child — using props. This is how React components communicate and become truly reusable.

Challenge: Before moving on, try modifying the profile card example. Add a "bio" field to the user object and display it. Or add a "Follow" button that toggles between "Follow" and "Following" (hint: you'll need React.useState from Part 1).

Happy coding!

More Deep Dives

What is React? — ReactJS Series Part 1
10 min read

What is React? — ReactJS Series Part 1

A beginner-friendly introduction to React. Learn what React is, why it exists, how it differs from vanilla JavaScript, and build your first component.

ReactJavaScript+3
Feb 21, 2026
Read
Claude Code: Agent Teams, MCP Servers & CI/CD Pipelines
20 min read

Claude Code: Agent Teams, MCP Servers & CI/CD Pipelines

Go multi-agent with Claude Code. Master agent teams, build custom MCP integrations, automate with GitHub Actions, and create CI/CD pipelines that code for you.

Claude CodeMCP+5
Feb 25, 2026
Read
Claude Code Remote Control: Continue Terminal Sessions From Your Phone
10 min read

Claude Code Remote Control: Continue Terminal Sessions From Your Phone

Learn how Remote Control lets you continue Claude Code sessions from your phone, tablet, or any browser — while everything runs locally on your machine.

Claude CodeRemote Control+5
Feb 25, 2026
Read
Code to Canvas: Turning Production Code into Editable Figma Designs
16 min read

Code to Canvas: Turning Production Code into Editable Figma Designs

Learn how Claude Code + Figma's MCP server turns your running UI into editable Figma layers — and back. The complete bidirectional design-code workflow.

FigmaClaude Code+5
Feb 25, 2026
Read
Mastering Claude Code: Skills, Memory, Tokens & Power-User Secrets
22 min read

Mastering Claude Code: Skills, Memory, Tokens & Power-User Secrets

Go beyond basics. Master CLAUDE.md context, auto memory, custom skills, hooks, subagents, token optimization, and the workflows that 10x your productivity with Claude Code.

Claude CodeAI+5
Feb 24, 2026
Read
Claude Code: The Agentic Coding Tool That Lives in Your Terminal
14 min read

Claude Code: The Agentic Coding Tool That Lives in Your Terminal

Master Claude Code — Anthropic's AI coding agent. Learn setup, agentic workflows, MCP servers, hooks, CLAUDE.md, and how it compares to Cursor and Copilot.

Claude CodeAI+5
Feb 23, 2026
Read
View All Dives

Explore more content