HTML to JSX Converter
Convert HTML to React JSX instantly in your browser. Handles className, htmlFor, inline style objects, camelCase events, self-closing tags, and more. Free, no signup.
- Runs in your browser
- Your data never leaves your browser
- Free · No Sign-Up
Scan with WeChat to share this tool
Examples, details and FAQ Worked examples, how it compares with other tools, and answers to common questions.
Conversion Rules
| HTML | JSX |
|---|---|
class="..." | className="..." |
for="..." | htmlFor="..." |
style="color:red" | style={{ "color": "red" }} |
onclick="save()" | onClick={(event) => { save() }} |
ondblclick="..." / onmouseover="..." | onDoubleClick={...} / onMouseOver={...} |
tabindex | tabIndex |
readonly | readOnly |
maxlength | maxLength |
colspan | colSpan |
rowspan | rowSpan |
crossorigin | crossOrigin |
contenteditable | contentEditable |
autocomplete, novalidate, srcset, datetime, spellcheck | autoComplete, noValidate, srcSet, dateTime, spellCheck |
http-equiv, accept-charset | httpEquiv, acceptCharset |
<br> | <br /> |
<img src="..."> | <img src="..." /> |
<input ...> | <input ... /> |
<!-- comment --> | {/* comment */} |
Text {name}, a < b | {name}, a < b |
Common Use Cases
- Migrating static HTML templates into React components
- Copying HTML snippets from design tools (Figma, Webflow) into JSX files
- Learning the differences between HTML and JSX attribute naming
- Converting email HTML templates for use in React email libraries
- Quickly adapting third-party HTML widgets for React projects
Example
Input:
<label for="email" class="lbl">Email</label>
<input id="email" type="email" required>
<div style="background-image: url('a.png'); font-size:14px">x</div>
<!-- footer -->
Output:
<label htmlFor="email" className="lbl">Email</label>
<input id="email" type="email" required />
<div style={{ "backgroundImage": "url('a.png')", "fontSize": "14px" }}>x</div>
{/* footer */}
A login form shows several rules at once. The input
<form action="/login" method="post" novalidate>
<label for="user" class="field-label">Username</label>
<input id="user" name="user" autocomplete="username" maxlength="32" autofocus>
<button type="submit" onclick="track("login")">Sign in</button>
</form>
becomes
<form action="/login" method="post" noValidate>
<label htmlFor="user" className="field-label">Username</label>
<input id="user" name="user" autoComplete="username" maxLength="32" autoFocus />
<button type="submit" onClick={(event) => { track("login") }}>Sign in</button>
</form>
Six attribute names change (novalidate, for, class, autocomplete, maxlength and the boolean autofocus), the void <input> gets />, and the onclick string becomes an arrow function with " decoded back to ". Without the rename, React DOM prints a development warning such as “Invalid DOM property autocomplete. Did you mean autoComplete?”, so pasting unconverted HTML usually works but floods the console. The attribute names come from the same table React uses to suggest them (possibleStandardNames.js in react-dom).
data-* and aria-* attributes stay hyphenated, as React expects. Numeric attributes stay strings, such as colSpan="2"; React accepts them.
What You Still Change by Hand
| Converter output | Problem in React | Change to |
|---|---|---|
onClick={(event) => { save(); return false; }} | The code runs in an arrow function: this is not the element, and return false does not cancel the default action | event.currentTarget, event.preventDefault(), or pass the function: onClick={save} |
<input type="checkbox" checked> | A checked prop without onChange makes a read-only field | defaultChecked |
<option selected> | React sets the selection on <select> | <select defaultValue="..."> |
<textarea>hi</textarea> | <textarea> does not accept children | <textarea defaultValue="hi" /> |
style="color:red !important" (no output) | Refused: a React style object cannot keep !important, so the output is cleared | Move the rule to a class in your CSS, or drop !important |
| Two or more top-level elements | A component returns one element | Wrap them in <>...</> |
<path stroke-width="2"> | SVG attributes are not converted | Use SVG to JSX |
Limits
- Attribute values are copied as written. Only attribute names change, so
href="/search?for=1&class=2"stays the same. This is what the htmltojsx converter does too. Two values change:stylebecomes an object, and the code of an event handler goes into(event) => { ... }, because React needs a function, not a string. Entities such as"in that code are decoded. Anon*attribute that is not a DOM event, such asonfooon a custom element, is kept as written. - Text keeps its characters. In text between tags,
{,},<and>are written as{,},<and>, which JSX turns back into the same characters, so<p>{name}</p>renders the text{name}instead of reading a variable. Other text is copied as is, and a full document keeps its<!DOCTYPE>,<html>,<head>, and<body>. Paste only the part that goes into the component. - Styles that cannot be kept are refused.
!important, a property written twice (color:red;color:blue, often a CSS fallback), CSS comments, escaped property names and unclosed quotes or brackets stop the conversion. The output is cleared, Copy is disabled and the status line names the character position in the style, for example “Cannot convert style at position 11: !important cannot be preserved in a React style object”. Other values, includingurl(data:…;base64,…)and custom properties like--accent, are copied character for character as JSON strings. - No component wrapper. The output is markup. Put it in the
return (...)of your component. - No HTML parsing or repair. The converter rewrites opening tags it can match with a pattern; it does not build a DOM. Unclosed tags stay unclosed, and an attribute written twice (
class="a" CLASS="b") becomes twoclassNameprops, which JSX does not allow. Paste markup that already validates. - Comments. A
*/inside an HTML comment is written as* /, so the JSX comment does not end early.
FAQ
What does an HTML to JSX converter do?
It transforms standard HTML markup into valid React JSX syntax. Key changes include renaming class to className, for to htmlFor, converting inline styles to JavaScript objects, renaming event attributes to React's camelCase names and wrapping their code in a function, and adding explicit self-closing slashes to void elements.
Why is className used instead of class in JSX?
JSX is compiled to JavaScript, and class is a reserved keyword in JavaScript. React uses className to avoid the collision. The converter handles this rename automatically.
How are inline styles converted?
HTML inline styles use a string: style="color: red; font-size: 14px". JSX requires an object, so the converter writes style={{ "color": "red", "fontSize": "14px" }}. It splits declarations only at top-level semicolons, so a semicolon inside quotes or url(data:…) stays in the value, keeps custom properties such as --accent as written, and copies each value exactly. A style that a React style object cannot keep (!important, the same property twice, a CSS comment, an unclosed quote or bracket) is refused: the output is cleared, Copy is disabled and the status line gives the character position.
What do HTML comments become in JSX?
HTML comments (<!-- text -->) are converted to JSX expression comments ({/* text */}), the only form React's JSX parser accepts.
Is anything sent to a server?
No. The conversion runs in your browser using JavaScript. No data is transmitted.