The difference between JSX and HTML comes down to one rule: JSX is JavaScript, and HTML is a markup language the browser parses directly. JSX looks like HTML but compiles into JavaScript objects, so it is stricter about tags, attribute names, and how values are written.
A quick example shows the shift. HTML writes a class attribute; JSX writes the same idea with a camelCase prop:
function Button() {
return <button className="primary">Save</button>;
}React renders a button with the CSS class "primary." The rename exists because class is a reserved word in JavaScript, and JSX turns attributes into object properties.
JSX vs HTML at a glance
The table below lists the differences you will hit most often when moving an HTML mockup into a React component.
| HTML | JSX | Why it changes |
|---|---|---|
| class attribute | className | class is reserved in JavaScript |
| for attribute | htmlFor | for is reserved in JavaScript |
| tabindex | tabIndex | camelCase naming |
| readonly | readOnly | camelCase naming |
| style="color: red" | style with an object | styles are objects |
| unclosed img tag | self-closing img | every tag closes |
Two groups of attributes keep their hyphens in JSX: aria attributes and data attributes. Everything else follows camelCase.
Attributes use camelCase
HTML attribute names are lowercase. JSX converts most of them to camelCase because they become JavaScript object properties, and JavaScript prefers camelCase.
The event attribute onload becomes onLoad, and the input attribute maxlength becomes maxLength. React prints a warning with the correct spelling when you get one wrong, so the mistake is easy to spot in the browser console. Think of the attribute as a JavaScript property: the name has to be a valid property name, which is why the hyphens disappear.
<input maxLength={40} onLoad={handleLoad} />This input enforces a 40 character limit and runs the load handler when it finishes loading. The visible result matches the HTML version, but the names follow JavaScript rules.
Every tag must close
HTML forgives unclosed tags. A list item or image often works even when the closing tag is left out. JSX does not allow that.
<img src="avatar.png" alt="Profile" />
<br />The image and line break are self-closing here. If you paste them as plain HTML, React shows a build error until the slash is added. JSX needs a closing slash so the compiler always knows where an element ends, with no ambiguity to resolve from context.
Inline styles are objects
HTML styles are strings. JSX styles are JavaScript objects with camelCase property names, so background-color becomes backgroundColor.
<p style={{ color: "crimson", fontSize: 18 }}>
Keep moving.
</p>The paragraph renders in crimson text at 18 pixels. The double braces are not a new syntax: the outer pair opens a JavaScript expression, and the inner pair is the style object itself. Margin and padding work the same way, so margin-top becomes marginTop and padding-left becomes paddingLeft.
Expressions replace static text
The biggest behavioral difference is that JSX can read JavaScript values. Where HTML needs a script to swap text, JSX embeds an expression directly.
const name = "Maya";
function Welcome() {
return <h1>Hello, {name}</h1>;
}The heading shows "Hello, Maya." The guide on rendering variables and expressions in JSX walks through what you can put between those braces.
Which should you use?
You never choose between JSX and HTML at the same level. HTML is what the browser renders in the end, and JSX is the syntax you write in source files.
A common false equivalence is treating JSX as a string of HTML. It is not. It compiles to objects, which is why the rules above exist.
For a full walk through those rules, the guide on what JSX is covers the syntax itself, and the guide on JSX attributes and inline styles goes deeper into styles and comments.
Rune AI
Key Insights
- JSX compiles to JavaScript; HTML is parsed directly by the browser.
- Most attributes switch to camelCase, such as className and htmlFor.
- Every JSX tag must be closed, including img and br.
- Inline styles are objects with camelCase property names.
- aria-* and data-* attributes keep their hyphens.
Frequently Asked Questions
Why does JSX use className instead of class?
Can I write regular HTML inside a React component?
Why do inline styles use two sets of curly braces?
Conclusion
JSX and HTML share a visual shape, but JSX is JavaScript. It closes every tag, renames reserved attributes with camelCase, and replaces static style strings with objects. Learning those differences turns any HTML mockup into working React markup.
More in this topic
How to Build a Dropdown Menu in React
Build a React dropdown menu with the ARIA menu button pattern. Handle open and close, keyboard arrows, and clicks outside the menu.
How to Animate React Components with Motion
Animate React components with the Motion library. Set up motion, add enter, hover, and exit animations, and respect reduced motion.
Headless UI Components Explained: Logic Without Locked Styling
Understand headless UI components and how libraries like Radix give you unstyled, accessible behavior that you style yourself.