iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

JSX

JSX is the syntax that lets you write HTML-flavoured templates inside JavaScript. It compiles to plain function calls — nothing magic — but its rules for attributes, expressions, conditionals, and lists are where most React beginners trip.

Expressions, attrs, children, gotchas

EXAMPLE
// 1) JSX is JavaScript — compiles to React.createElement (or jsx runtime)
// JSX:
const el = <h1 className="title">Hello, {user.name}</h1>;
// Compiled:
const el = React.createElement('h1', { className: 'title' }, 'Hello, ', user.name);

// 2) Any single expression inside { }
const price = 4.99;
<p>Total: ${price.toFixed(2)}</p>
<p>{user.firstName + ' ' + user.lastName}</p>
<p>{Date.now()}</p>
<p>{1 + 1}</p>

// Statements (if/for) are NOT expressions. Use ternaries, &&, .map().

// 3) Attributes
//   className not class
//   htmlFor   not for
//   tabIndex  not tabindex   (camelCase for almost everything)
//   style takes an object: { backgroundColor: 'red', fontSize: 14 }
//   data-* and aria-* keep their dash form

<input type="text" id="name" tabIndex={1} aria-label="Name" />
<label htmlFor="name">Name</label>
<div className="card" style={{ padding: 16, borderRadius: 8 }}>…</div>

// 4) Boolean attributes
<button disabled>Save</button>          // disabled={true}
<button disabled={isSaving}>Save</button>
<input checked={agreed} readOnly />     // readOnly, not readonly

// 5) Children — strings, numbers, elements, arrays, fragments
<section>
    Plain text
    <em>emphasised</em>
    {[<p key="a">A</p>, <p key="b">B</p>]}
</section>

// 6) Conditional rendering
{loggedIn && <Avatar user={user} />}
{loggedIn ? <Welcome user={user} /> : <SignInPrompt />}
{count === 0 && <EmptyState />}
{count > 0 && <p>{count} items</p>}

// CAUTION: 0 is FALSY but RENDERS as '0'.
{count && <p>{count} items</p>}            // 0 → renders the literal 0; use count > 0 or count != null

// 7) Lists — every child of an array needs a stable key
<ul>
    {todos.map((t) => (
        <li key={t.id} className={t.done ? 'done' : ''}>{t.text}</li>
    ))}
</ul>
// NEVER use the array index as key for lists that reorder, filter, or splice mid-list.

// 8) Fragments — return multiple elements without a wrapper
function Group() {
    return (
        <>
            <h2>Group</h2>
            <p>members…</p>
        </>
    );
}

// Keyed fragments (when in a list)
{rows.map((r) => (
    <React.Fragment key={r.id}>
        <td>{r.name}</td>
        <td>{r.email}</td>
    </React.Fragment>
))}

// 9) Components — uppercase tags
<UserCard user={user} />            // component
<usercard user={user} />            // DOM tag <usercard>, ignored unless registered

// 10) Spreading props
const inputProps = { type: 'email', autoComplete: 'email', required: true };
<input {...inputProps} value={email} onChange={onChange} />
// Later spreads override earlier ones.

// 11) Children prop
function Card({ title, children }) {
    return (
        <section className="card">
            <h3>{title}</h3>
            <div>{children}</div>
        </section>
    );
}
<Card title="Profile">
    <p>email: mara@example.com</p>
</Card>

// 12) HTML entities + escaping
// JSX does NOT auto-decode HTML entities the way HTML does.
// Use string literals or curly with the entity:
<p>{'\u00A9'} 2024</p>            // copyright
<p>&copy; 2024</p>                  // works in JSX (limited entities)
<p>{'a & b'}</p>                    // safest — emits literal '&'

// 13) Setting raw HTML — last-resort escape hatch
<div dangerouslySetInnerHTML={{ __html: sanitisedHtml }} />
// dangerously — only when you've sanitised the input (DOMPurify, etc.)

// 14) Event handlers — camelCase, value is a function
<button onClick={handleClick}>Save</button>
<input onChange={(e) => setName(e.target.value)} />
<form onSubmit={(e) => { e.preventDefault(); submit(); }}>

// SyntheticEvent — React's cross-browser wrapper; e.target, e.currentTarget, e.preventDefault().

// 15) Inline functions vs memoized handlers
// Inline is fine for most cases. For memoized children (React.memo), use useCallback
// to keep handler identity stable:
const onSave = useCallback((id) => save(id), []);
<Row onSave={onSave} />

// 16) Whitespace rules
// Adjacent text is collapsed to a single space.
// Blank lines between tags do NOT render whitespace.
// Inline {' '} when you need an explicit space.
<span>{firstName}{' '}{lastName}</span>

// 17) Returning null is valid — renders nothing
function Maybe({ when, children }) {
    return when ? children : null;
}

// 18) JSX vs createElement — TypeScript + tooling
// Modern setups use the jsx runtime (no React import needed for JSX). Older setups
// require 'import React from "react"' even when React isn't referenced.

// 19) Common bugs
//   • Lowercase component name → React treats as DOM tag, fails silently
//   • class instead of className → DOM warning, no class applied
//   • {count && <X/>} when count can be 0 → renders '0'
//   • Reusing a key after deleting/reordering → wrong state attaches to wrong row
//   • Returning a non-element/non-array from a component → 'Objects are not valid as a React child'
//   • Comments inside JSX must be in braces: {/* like this */} — // and /* */ outside braces only
//   • Inline style with px: { width: 200 } sets 200px; { width: '200px' } also works; { width: 0.5 } sets 0.5px

Why it matters

JSX is a thin wrapper around React.createElement: expressions in {}, camelCase attributes, every list child needs a stable key, and 0 renders as “0” instead of nothing. Lean on <>…</> fragments to avoid wrapper divs, and use && for present/absent and ternaries for either/or rendering.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
const name = 'Ada';
const el = <h1 className="hi">Hello, {name}!</h1>;
Try it Yourself »

Exercise

JSX uses this attribute instead of "class".

<div ="card">…</div>

Test yourself

Q1. JSX class attribute is written as…
Q2. A component must return…
Q3. JS expressions inside JSX go in…

Discussion

Loading…