JSX Syntax: Writing HTML in JavaScript

Making React Development Intuitive and Powerful

Overview

Welcome to our deep dive into JSX! Today, we'll explore JSX syntax, which makes writing React components feel natural and intuitive. Think of JSX as a bridge between HTML and JavaScript - it looks like HTML but has the full power of JavaScript. By the end of this lesson, you'll be comfortable writing JSX and understanding how it works under the hood.

What is JSX?

JSX (JavaScript XML) is like a recipe written in a chef's shorthand - it looks familiar but has special powers. It's a syntax extension for JavaScript that lets you write HTML-like code directly in your JavaScript files.

graph LR A[JSX Code] -->|Babel Compiler| B[JavaScript Code] B -->|Browser| C[Rendered UI] subgraph "What You Write" D["<h1>Hello</h1>"] end subgraph "What Browser Sees" E["React.createElement('h1', null, 'Hello')"] end D --> A B --> E

JSX vs HTML: Key Differences

While JSX looks like HTML, it has some important differences. Think of JSX as HTML's smarter cousin:

1. ClassName Instead of Class


// HTML
<div class="container">Content</div>

// JSX
<div className="container">Content</div>

// Why? 'class' is a reserved word in JavaScript
            

2. CamelCase for Attributes


// HTML
<div onclick="handleClick()" tabindex="0">Click me</div>

// JSX
<div onClick={handleClick} tabIndex={0}>Click me</div>

// JSX uses camelCase for all attributes
            

3. Self-Closing Tags Must Close


// HTML (both work)
<img src="photo.jpg">
<br>

// JSX (must self-close)
<img src="photo.jpg" />
<br />

// Think of it as being more strict about closing tags
            

Embedding JavaScript in JSX

The real magic of JSX is embedding JavaScript expressions using curly braces {}. It's like adding dynamic ingredients to your recipe:


function Greeting() {
    const name = "Sarah";
    const hour = new Date().getHours();
    
    // JavaScript expressions in curly braces
    return (
        <div>
            <h1>Hello, {name}!</h1>
            <p>It's {hour} o'clock.</p>
            <p>2 + 2 = {2 + 2}</p>
            <p>Today is {new Date().toLocaleDateString()}</p>
        </div>
    );
}
            

JSX is an Expression Too

JSX itself is an expression, which means you can use it in JavaScript logic:


function getGreeting(user) {
    if (user) {
        return <h1>Hello, {user.name}!</h1>;
    }
    return <h1>Hello, Stranger!</h1>;
}

// Using JSX in a ternary operator
const element = (
    <div>
        {isLoggedIn ? <UserDashboard /> : <LoginForm />}
    </div>
);

// Assigning JSX to variables
const button = <button>Click me</button>;
const header = <h1>Welcome</h1>;
            

JSX Children

JSX elements can contain children, just like HTML. Think of it as nesting ingredients in a recipe:


// Single child
const element = <h1>Hello, world!</h1>;

// Multiple children
const container = (
    <div>
        <h1>Title</h1>
        <p>Paragraph</p>
        <button>Click me</button>
    </div>
);

// Children can be JavaScript expressions
const list = (
    <ul>
        {[1, 2, 3].map(num => (
            <li key={num}>Item {num}</li>
        ))}
    </ul>
);
            

JSX Prevents Injection Attacks

JSX automatically escapes values to prevent XSS attacks. It's like having a food safety inspector for your code:


const userInput = '<script>alert("XSS!")</script>';

// This is safe - JSX escapes the content
const element = <div>{userInput}</div>;

// Renders as text, not executable code:
// <div>&lt;script&gt;alert("XSS!")&lt;/script&gt;</div>
            

JSX Represents Objects

Under the hood, JSX creates React elements. It's like a recipe that gets converted to cooking instructions:


// This JSX:
const element = (
    <h1 className="greeting">
        Hello, world!
    </h1>
);

// Is compiled to:
const element = React.createElement(
    'h1',
    {className: 'greeting'},
    'Hello, world!'
);

// Which creates this object:
const element = {
    type: 'h1',
    props: {
        className: 'greeting',
        children: 'Hello, world!'
    }
};
            

JSX Style Attributes

Styles in JSX use JavaScript objects with camelCase properties:


// CSS styles as JavaScript objects
const divStyle = {
    color: 'blue',
    backgroundColor: 'lightgray',
    padding: '10px',
    borderRadius: '5px'
};

function StyledComponent() {
    return (
        <div style={divStyle}>
            Styled with JavaScript object
        </div>
    );
}

// Inline styles
function InlineStyled() {
    return (
        <div style={{
            color: 'red',
            fontSize: '20px',
            marginTop: '10px'
        }}>
            Inline styled text
        </div>
    );
}
            

Conditional Rendering in JSX

JSX supports various patterns for conditional rendering:


function ConditionalExample({ isLoggedIn, notifications }) {
    return (
        <div>
            {/* Ternary operator */}
            {isLoggedIn ? <LogoutButton /> : <LoginButton />}
            
            {/* Logical AND operator */}
            {notifications.length > 0 && (
                <span>You have {notifications.length} notifications</span>
            )}
            
            {/* IIFE (Immediately Invoked Function Expression) */}
            {(() => {
                if (isLoggedIn) {
                    return <Dashboard />;
                } else {
                    return <LandingPage />;
                }
            })()}
        </div>
    );
}
            

Lists and Keys in JSX

When rendering lists, each item needs a unique key. Think of keys as name tags at a party:


function TodoList({ todos }) {
    return (
        <ul>
            {todos.map(todo => (
                <li key={todo.id}>
                    {todo.text}
                </li>
            ))}
        </ul>
    );
}

// Keys help React identify which items have changed
const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) =>
    <li key={number.toString()}>
        {number}
    </li>
);
            

JSX Fragments

Sometimes you need to return multiple elements without adding extra DOM nodes:


// Using Fragment (long syntax)
function FragmentExample() {
    return (
        <React.Fragment>
            <h1>Title</h1>
            <p>Paragraph</p>
        </React.Fragment>
    );
}

// Using Fragment (short syntax)
function ShortFragmentExample() {
    return (
        <>
            <h1>Title</h1>
            <p>Paragraph</p>
        </>
    );
}

// Fragments with keys
function KeyedFragments({ items }) {
    return (
        <dl>
            {items.map(item => (
                <React.Fragment key={item.id}>
                    <dt>{item.term}</dt>
                    <dd>{item.description}</dd>
                </React.Fragment>
            ))}
        </dl>
    );
}
            

JSX Comments

Comments in JSX must be wrapped in curly braces:


function CommentExample() {
    return (
        <div>
            {/* This is a JSX comment */}
            <h1>Hello</h1>
            
            {/* 
               Multi-line
               JSX comment 
            */}
            
            {
                // Single line comment inside braces
            }
            
            <p>Paragraph</p>
        </div>
    );
}
            

Common JSX Gotchas

1. Returning Multiple Elements


// ❌ Wrong - can't return multiple elements
function Wrong() {
    return (
        <h1>Title</h1>
        <p>Paragraph</p>
    );
}

// ✅ Correct - wrap in a parent element or fragment
function Correct() {
    return (
        <>
            <h1>Title</h1>
            <p>Paragraph</p>
        </>
    );
}
            

2. JavaScript Expressions Only


// ❌ Wrong - statements aren't allowed
function Wrong() {
    return (
        <div>
            {if (true) { return "Yes" }}
        </div>
    );
}

// ✅ Correct - use expressions
function Correct() {
    return (
        <div>
            {true ? "Yes" : "No"}
        </div>
    );
}
            

3. Objects as Children


// ❌ Wrong - objects can't be rendered directly
function Wrong() {
    const user = { name: "John", age: 30 };
    return <div>{user}</div>;
}

// ✅ Correct - render object properties
function Correct() {
    const user = { name: "John", age: 30 };
    return <div>{user.name}, {user.age}</div>;
}
            

JSX Best Practices

graph TD A[JSX Best Practices] --> B[Use Semantic HTML] A --> C[Keep Components Small] A --> D[Extract Complex Logic] A --> E[Use Descriptive Names] B --> F[<header>, <main>, <article>] C --> G[Single Responsibility] D --> H[Helper Functions] E --> I[UserProfile not UP]

// Good JSX practices
function UserProfile({ user }) {
    // Extract complex logic
    const getStatusColor = (status) => {
        switch(status) {
            case 'active': return 'green';
            case 'inactive': return 'gray';
            case 'banned': return 'red';
            default: return 'black';
        }
    };

    // Use semantic HTML
    return (
        <article className="user-profile">
            <header>
                <h2>{user.name}</h2>
                <span 
                    className="status"
                    style={{ color: getStatusColor(user.status) }}
                >
                    {user.status}
                </span>
            </header>
            
            <section className="user-details">
                <p>Email: {user.email}</p>
                <p>Joined: {new Date(user.joinDate).toLocaleDateString()}</p>
            </section>
        </article>
    );
}
            

Practice Exercises

Exercise 1: JSX Conversion

Convert this HTML to proper JSX:


<!-- Convert this HTML to JSX -->
<div class="card">
    <img src="profile.jpg" alt="Profile">
    <h3 class="name">John Doe</h3>
    <p>Web Developer</p>
    <button onclick="handleContact()">Contact</button>
</div>
            

Exercise 2: Dynamic Content

Create a component that displays the current time and updates every second:


function Clock() {
    // Use state to track time
    // Update time every second
    // Display formatted time
}
            

Exercise 3: Conditional Rendering

Build a notification component that shows different messages based on status:


function Notification({ type, message }) {
    // Show different styles/icons based on type
    // Types: 'success', 'error', 'warning', 'info'
}
            

Key Takeaways

What's Next?

In our next lesson, we'll explore Components and Props in depth. We'll learn how to create reusable components, pass data between them, and build complex UIs from simple building blocks.

Homework