React: From Components to Production · Components and JSX
JSX Essentials
Write markup in JavaScript: expressions, attributes, fragments and rules.
JSX is syntax that compiles to React.createElement/jsx() calls. Rules: return a single root (use fragments <>...</>), close every tag, use className and htmlFor, camelCase event handlers (onClick), and embed JavaScript expressions in {}. Inline styles take objects. JSX escapes values by default, protecting against XSS unless you use dangerouslySetInnerHTML.
type Props = { user: { name: string; avatarUrl: string; isAdmin: boolean } };
export function UserBadge({ user }: Props) {
const initials = user.name.split(" ").map((p) => p[0]).join("");
return (
<>
<img className="avatar" src={user.avatarUrl} alt={`${user.name}'s avatar`} width={40} height={40} />
<span style={{ fontWeight: 600 }}>{user.name}</span>
{user.isAdmin && <span className="badge">Admin</span>}
<span aria-hidden="true">{initials}</span>
</>
);
}
export function UserBadge({ user }) {
const initials = user.name.split(" ").map((p) => p[0]).join("");
return (
<>
<img className="avatar" src={user.avatarUrl} alt={`${user.name}'s avatar`} width={40} height={40} />
<span style={{ fontWeight: 600 }}>{user.name}</span>
{user.isAdmin && <span className="badge">Admin</span>}
<span aria-hidden="true">{initials}</span>
</>
);
}
Common pitfalls
- Rendering
{count && <Badge />}when count is 0 — React renders0. - Using
dangerouslySetInnerHTMLwith unsanitized input. - Forgetting
alttext on images.
Key points
- JSX is JavaScript expressions + markup
- Values are escaped by default
- Use fragments for multiple roots
Further reading: react.dev: Writing markup with JSX
Practice questions
Why does {items.length && <List />} sometimes render '0'?
Answer
When items.length is 0, the expression evaluates to the number 0, which React renders. Use items.length > 0 && <List /> or a ternary.
How does JSX help prevent XSS?
Answer
React escapes strings embedded in JSX before inserting them into the DOM, so user content is treated as text. Only dangerouslySetInnerHTML bypasses this.
Open in the app to mark lessons complete, take notes and track your progress.