Paste HTML or SVG, get JSX React can actually render — in your browser
style="color:red" → style={{color: 'red'}}), and self-closes void tags. In the SVG tab it also renames hyphenated attributes to React's camelCase (stroke-width→strokeWidth) and can wrap the result as a named component with a props spread — svgr-style output, no build step. Everything runs locally with the open-source react-magic engine.| HTML / SVG | JSX | Why |
|---|---|---|
class | className | DOM property name, not attribute |
for | htmlFor | for is a JS reserved word |
tabindex | tabIndex | camelCase DOM property |
readonly | readOnly | camelCase DOM property |
maxlength | maxLength | camelCase DOM property |
autocomplete | autoComplete | camelCase DOM property |
colspan / rowspan | colSpan / rowSpan | camelCase DOM property |
srcset | srcSet | camelCase DOM property |
value (input) | defaultValue | uncontrolled input default |
stroke-width | strokeWidth | React SVG attributes are camelCase |
stroke-linecap | strokeLinecap | same |
stroke-dasharray | strokeDasharray | same |
fill-rule / clip-path | fillRule / clipPath | same |
font-size / text-anchor | fontSize / textAnchor | same |
xlink:href | xlinkHref | namespaced attrs camelCase in React |
xmlns:xlink | xmlnsXlink | same |
aria-*, data-* | unchanged | React expects the hyphens |
Boolean attributes come through bare (disabled), numeric strings become expressions (width={24}), and viewBox stays exactly as it is — already valid camelCase.
This page runs htmltojsx — the BSD-licensed converter from React's react-magic project, the engine behind React's own HTML→JSX playground — directly in your browser. It parses your markup into a real DOM tree, walks it, and re-serializes each node as JSX: attributes renamed to React's names, style strings converted to object literals, void elements self-closed, and text escaped where JSX needs it. The SVG tab layers a normalizer on top that renames hyphenated SVG attributes to React's camelCase forms (the same mapping the svgr toolchain applies) and can wrap the output as a named, exported component with a props spread on the root element.
Input:
<div class="hero" id="top"><h1 style="color:red">Hello</h1><p>Text & more <br/></p><input type="text" value="a" disabled><img src="x.png" alt="pic"></div>
Output (JSX mode):
<div className="hero" id="top"><h1 style={{color: 'red'}}>Hello</h1><p>Text & more <br /></p><input type="text" defaultValue="a" disabled /><img src="x.png" alt="pic" /></div>
Four conversions happened: class became className, the style string became a style object, the input's value became defaultValue (the uncontrolled-input form React expects in plain markup), and <br>, <input>, <img> self-closed — JSX requires it.
Input (a typical icon, with the attributes icon sets actually use):
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon"><polyline points="3 17 9 11 13 15 21 7"></polyline></svg>
Output (component mode, named ActivityIcon, props spread on):
export default function ActivityIcon(props) { return ( <svg xmlns="http://www.w3.org/2000/svg" width={24} height={24} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round" className="icon" {...props}> <polyline points="3 17 9 11 13 15 21 7" /> </svg> ); }
Paste the same SVG into React without conversion and the console fills with "Invalid DOM property" warnings while the stroke silently disappears — which is how most people find this tool.
onclick="doThing()" needs to become onClick={doThing} with a real function — no static converter can invent your handler.<script> and <link> don't belong in JSX at all; move them out.{{mustache}}, <% erb %>, and PHP tags pass through as literal text — strip them before converting.Because className is a property of the DOM API, not an HTML attribute name. React sets real DOM properties (element.className), and it does this at runtime, so JSX attribute names follow the property names: className, htmlFor, tabIndex. The converter renames all of them automatically.
HTML style strings become JavaScript objects. style="color:red" turns into style={{color: 'red'}}, and hyphenated CSS properties camel-case themselves: font-size becomes fontSize. The converter produces the object literal for you, quoted values included.
The message reads 'Invalid DOM property stroke-width. Did you mean strokeWidth?' React's SVG attributes are camelCase like its HTML ones, so stroke-width, stroke-linecap, clip-path, and fill-rule must become strokeWidth, strokeLinecap, clipPath, and fillRule. The SVG tab here renames them after converting — aria-* and data-* keep their hyphens, since React expects those verbatim.
Yes — the SVG tab does the conversion plus the wrapping that icon workflows expect: name the component, spread props onto the root element (svgr-style, so callers can set size and color), and export it as a default function component, optionally in TypeScript. That reproduces the output of the svgr toolchain without a build step.
No. The converter runs on the open-source htmltojsx engine (BSD-licensed, from React's react-magic project) directly in your browser tab. Paste in proprietary markup if you like — the network tab shows no requests after the engine loads.
JavaScript and CSS in script and style tags doesn't translate — JSX treats their contents as text, and React wants real event handlers (onclick becomes onClick as a function prop, which no static converter can invent). Web components, server-side includes, and template syntax (mustaches, ERB) come through literally. Convert markup, then wire behavior by hand.