Paste HTML on the left and this converter writes JSX on the right as you type: class becomes className, for becomes htmlFor, inline styles turn into camelCase objects, void tags like img and input are self-closed, comments move into braces, and several top-level elements get a fragment. The conversion runs only in your browser.
| HTML | JSX | Why |
|---|---|---|
| class="box" | className="box" | class is a reserved word in JavaScript |
| for="email" | htmlFor="email" | for is a reserved word too |
| style="font-weight: bold" | style={{ fontWeight: 'bold' }} | style takes an object with camelCase keys |
| <img src="a.png"> | <img src="a.png" /> | Every tag must be closed |
| onclick="go()" | onClick={go} | Events are camelCase and take a function |
| data-id="7", aria-label="Close" | unchanged | data- and aria- keep their dashes |
Updated
Copying a snippet from a template, an email builder or an icon set into a React component usually breaks on a dozen small differences. This tool applies the rules React documents for JSX, explains each change it made, and can wrap the result in a named component ready to paste.
The sample below is converted live; replace it with your own HTML.
<!-- Signup card -->
<div class="card" style="padding: 16px; border-radius: 12px; --accent: #4f98fb">
<label for="email">Email</label>
<input id="email" type="email" value="" tabindex="0" autofocus>
<button class="btn" onclick="subscribe()" aria-label="Subscribe">Join {free}</button>
</div>
<p>No spam.<br>Unsubscribe any time.</p><>
{/* Signup card */}
<div className="card" style={{ padding: '16px', borderRadius: '12px', '--accent': '#4f98fb' }}>
<label htmlFor="email">Email</label>
<input id="email" type="email" defaultValue="" tabIndex={0} autoFocus />
<button className="btn" onClick={() => { /* subscribe() */ }} aria-label="Subscribe">Join {'{'}free{'}'}</button>
</div>
<p>No spam.<br />Unsubscribe any time.</p>
</>| HTML | JSX |
|---|---|
| class | className |
| for | htmlFor |
| tabindex | tabIndex |
| readonly | readOnly |
| maxlength | maxLength |
| colspan / rowspan | colSpan / rowSpan |
| autocomplete | autoComplete |
| srcset | srcSet |
| crossorigin | crossOrigin |
| value on input | defaultValue |
| checked on input | defaultChecked |
| stroke-width | strokeWidth |
| fill-rule | fillRule |
| viewbox | viewBox |
React's own introduction to JSX boils the differences down to three rules: return a single root element, close every tag, and write most attribute names in camelCase. Almost everything the converter does is one of those three.
The exceptions are reserved words and the dashed families. class and for are renamed because JavaScript reserves them, while aria- and data- attributes keep their HTML spelling.
Inline scripts and event handler strings are code, not markup, so they need rewriting as functions in your component. The converter flags them instead of guessing.
Repeated blocks such as list items are often better as an array mapped to JSX. After converting, look for copy-pasted siblings and turn them into data plus a map call.
JSX compiles to JavaScript, where class is a reserved word. React therefore names the prop className. The same reasoning turns the label attribute for into htmlFor.
No. React's docs note that, for historical reasons, aria-* and data-* attributes are written exactly as in HTML, with dashes. Most other multi-word attributes become camelCase.
Pass an object to style with camelCase property names, for example style={{ fontWeight: 'bold', marginTop: 8 }}. React adds px to plain numbers for most properties. The outer braces open a JavaScript expression and the inner ones are the object.
A component can return only one element. Wrap siblings in a parent element or an empty fragment, written <> and </>. The converter does this for you when the HTML has more than one top-level node.
No. The conversion is plain JavaScript running in this page. Nothing you paste is uploaded or stored.
Related: React chart libraries, React icons guide, React Hook Form examples, React interview questions.
Start for free or see all free tools. We.Inc is free to start, with no card needed. AI building is on paid plans from $20 a month.
We.Inc is an AI-powered website builder you can resell under your own brand. Launch a branded client dashboard, bill on Stripe Connect, and deliver AI-generated websites in minutes. White-label plans start at $99 a month for 25 client sites, with a 7-day free trial and no per-site fees.