A Side-by-Side Cheat Sheet
JSX vs HTML
Quick reference for the differences between JSX and plain HTML — attributes, events, comments, booleans, style, void elements.
What you'll learn
- Translate common HTML to JSX
- Avoid the most common attribute-naming mistakes
A consolidated cheat sheet you can come back to.
Side By Side
| HTML | JSX |
|---|---|
<div class="x"> | <div className="x"> |
<label for="email"> | <label htmlFor="email"> |
<input type="text" readonly> | <input type="text" readOnly /> |
<input tabindex="0"> | <input tabIndex={0} /> |
<img src="me.png"> | <img src="me.png" /> (self-closed) |
<br> | <br /> |
onclick="doStuff()" | onClick={doStuff} |
style="color: red; font-size: 14px;" | style={{ color: "red", fontSize: 14 }} |
<!-- a comment --> | {/* a comment */} |
& / © | use the actual char, or {"©"} |
data-id="42" | data-id="42" (unchanged) |
aria-label="Save" | aria-label="Save" (unchanged) |
Events Are camelCase Props
<button onClick={handleClick} onMouseEnter={handleHover}>
Click me
</button> You pass a function, not a string. Inline arrow functions work too:
<button onClick={() => console.log("clicked")}>Click</button> Boolean Attributes
In HTML you write <input disabled>. In JSX you can do the same,
but it’s clearer to pass a JS boolean:
<input disabled /> // always disabled
<input disabled={isLoading} /> // disabled when isLoading Children Are Just Nested JSX
<section>
<header>
<h1>Title</h1>
</header>
<p>Body</p>
</section> Strings Need Quotes; Everything Else Needs Braces
<img src="me.png" /> // string literal
<img src={user.avatarUrl} /> // expression
<img src={`/u/${id}.png`} /> // template literal Self-Closing vs Open
| Element type | Example |
|---|---|
| Void HTML element | <img />, <br />, <input /> |
| Custom, no children | <Profile /> |
| With children | <Profile>…</Profile> |
Up Next
That weird <>...</> you’ve seen — Fragments.