What this tool does
The converter parses your input with the same rules browsers use, so it converts the tree a browser would build: a <p> that a <div> closes, an optional </li>, a <tbody> added to a table, an SVG tag such as linearGradient. It then writes JSX for React 19. Attribute names come from React's own list of DOM properties, so tabindex becomes tabIndex, readonly becomes readOnly, http-equiv becomes httpEquiv and stroke-width becomes strokeWidth; aria-* and data-* attributes, and the attributes of custom elements such as <my-widget>, stay as written. A style attribute becomes an object with camelCase keys (-webkit- becomes Webkit, -ms- becomes ms, and --custom properties stay quoted), a boolean attribute such as disabled becomes a bare prop, and numeric props such as tabIndex, colSpan and maxLength become numbers. By default, form values become defaultValue and defaultChecked, and <option selected> becomes a defaultValue on its <select>, because value without an onChange handler makes React render a read-only field. Text is escaped where JSX needs it: { and } become {"{"} and {"}"}, < and > become < and >. JSX joins lines and drops line breaks between tags, so where a space between inline content would be lost at a line break, the tool writes {" "}; spaces next to blocks, which browsers do not show, are left out. Text in <pre> and <textarea> is kept exactly, in a template literal. Comments become {/* … */}, an inline <script> becomes dangerouslySetInnerHTML, and for a full page only the <body> content is converted. Event handlers cannot be turned into code safely, so they are removed, kept as a comment in the tag, and listed with the React event to use instead.
Example input and output
<form class="search" action="/search">
<label for="q">Search</label>
<input id="q" name="q" type="search" value="react" autofocus>
<label><input type="checkbox" name="exact" checked> Exact match</label>
<select name="sort">
<option value="new">Newest</option>
<option value="top" selected>Top</option>
</select>
<button type="submit" tabindex="0" onclick="track()">Go</button>
</form><form className="search" action="/search">
<label htmlFor="q">Search</label>{" "}
<input id="q" name="q" type="search" defaultValue="react" autoFocus />{" "}
<label>
<input type="checkbox" name="exact" defaultChecked /> Exact match
</label>{" "}
<select name="sort" defaultValue="top">
<option value="new">Newest</option>
<option value="top">Top</option>
</select>{" "}
<button type="submit" tabIndex={0} /* onclick="track()" */>Go</button>
</form>The line breaks between the fields are spaces on the page, so they become {" "}. The onclick handler is listed as removed: write onClick={track} in your component.
<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">
<circle cx="12" cy="12" r="10"/>
<path d="m9 12 2 2 4-4"/>
</svg>export default function CheckIcon() {
return (
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
className="icon"
>
<circle cx="12" cy="12" r="10" />
<path d="m9 12 2 2 4-4" />
</svg>
);
}With Component, the name CheckIcon and Drop SVG xmlns. viewBox keeps its case, and the presentation attributes are camelCased.
<p class="hint">Templates use {name} and {{ count }} — see the <a href="/docs/templates/placeholders">placeholder guide</a> for the full list.</p>
<pre>npm run build
npm start</pre><>
<p className="hint">
Templates use {"{"}name{"}"} and {"{{"} count {"}}"} — see the{" "}
<a href="/docs/templates/placeholders">placeholder guide</a> for the full
list.
</p>
<pre>{`npm run build
npm start`}</pre>
</>Two root elements are wrapped in a fragment. — stays, because JSX reads it the same way; turn on Decode entities to get the character instead.
Common errors and fixes
- Invalid DOM property `class`. Did you mean `className`?
- class and for are reserved words in JavaScript, and React uses the DOM property names className and htmlFor. React still renders class, but warns. The converter renames both, along with the other attributes React spells differently, such as tabindex and stroke-width.
- The `style` prop expects a mapping from style properties to values, not a string.
- In JSX, style takes an object: style="margin-top: 4px" becomes style={{ marginTop: "4px" }}. React throws on a string, so the page does not render at all. The converter splits declarations correctly even when a value contains a semicolon, as in url("a;b.png").
- You provided a `value` prop to a form field without an `onChange` handler.
- In React, value makes a field controlled: React keeps it at that value, so typing does nothing. For a starting value the user can change, use defaultValue (and defaultChecked for checkboxes), which is the default here. If you need a controlled field, turn off Uncontrolled form fields and add state with an onChange handler.
- JSX element 'br' has no corresponding closing tag.
- HTML lets <br>, <img> and <input> stand alone, but JSX needs every element closed. The converter writes <br />, <img />, <input /> and closes empty elements such as <div /> too.
- Unexpected token. Did you mean `{'}'}` or `}`?
- TypeScript rejects } and > in JSX text, and { starts an expression. The converter writes braces as {"{"} and {"}"}, and < and > as < and >, so code samples and template syntax such as {{ name }} show as written.
- JSX expressions must have one parent element.
- A JSX expression returns one element. When you paste several siblings, the converter wraps them in a fragment, <>…</>, which adds nothing to the page.
- Expected `onClick` listener to be a function, instead got a value of `string` type.
- HTML handlers are strings of code; React handlers are functions. The converter removes onclick="…", keeps it as a comment in the tag, and names the React prop to use, such as onClick={handleClick}.
Common use cases
- Turning a static HTML template or a landing page section into a React component
- Pasting an SVG icon from Figma, Illustrator, Inkscape or an icon set into JSX
- Moving Bootstrap or Tailwind examples into a React or Next.js project
- Converting markup from a CMS, an email builder or DevTools into JSX
- Checking what React would warn about in a piece of HTML before you paste it
Privacy and security notes
- Your markup is parsed and converted by JavaScript in this browser tab. It is not sent to DevPrix or stored on a server.
- The input is never rendered or run: the JSX is shown as highlighted text, so scripts, event handlers, iframes and images in it do nothing, and nothing they refer to is fetched.
- Share copies a link that carries your input after the # in the URL. Browsers do not send that part to servers, but anyone you give the link to can read it.
Frequently asked questions
Why is there {" "} in the output?
JSX handles whitespace differently from HTML. It trims each line and drops line breaks between tags, so a space that sat at the end of a line next to a tag would be lost. In HTML that space is visible: it separates "Read the" from a link, or two form fields. Where a line break would lose a space, the converter writes {" "}. Spaces next to block elements, such as between two <div>s, are not shown by browsers, so they are left out.
What happens to onclick and other event handlers?
They are removed, because an HTML handler is a string of code that runs in the page's global scope, with its own this and event, and it cannot be turned into a React function safely. With Keep comments on, the original stays as a comment in the tag, such as /* onclick="save()" */, and the Warnings list names the React prop to use, such as onClick={…}. Move the code into a function in your component and pass it to that prop.
Should I use defaultValue or value?
defaultValue (and defaultChecked) sets the starting value and lets the user change it: React calls this an uncontrolled field. value (and checked) makes the field controlled: React keeps it at that value until you update it from an onChange handler, and warns when there is none. The converter uses defaultValue by default, and moves <option selected> to the <select>, as React asks. Turn off Uncontrolled form fields to get value and checked, then add state.
Does it work with SVG icons from Figma or Illustrator?
Yes. Presentation attributes such as stroke-width and fill-rule become strokeWidth and fillRule, xlink:href becomes xlinkHref, viewBox and preserveAspectRatio keep their case, and tags such as linearGradient and clipPath are restored even when the file wrote them in lowercase. The <?xml?> declaration is dropped, and so are the inkscape:, sodipodi: and rdf: elements and attributes that drawing apps add, since React cannot render namespaced names. Turn on Drop SVG xmlns for inline icons: inside an HTML page the namespace is not needed.
What is the difference between JSX and TSX output?
The markup is the same, and numeric props such as tabIndex are always numbers, as React's TypeScript types expect. In TSX, a style object that sets a CSS variable such as --accent is cast with as CSSProperties, because TypeScript does not know custom properties, and a component gets the matching import type line. The Warnings list also notes elements React's types do not include, such as <font> or a custom element, which need a type declaration.
Why did my <script> become dangerouslySetInnerHTML?
In JSX the text inside an element is escaped, which would break a script's quotes and < signs, so the code goes into dangerouslySetInnerHTML as a template literal. React does not run a script it adds while rendering in the browser, only one that arrives in server-rendered HTML, so the tool flags inline scripts. Load the code with an import, in useEffect, or with your framework's script component, such as next/script. JSON-LD blocks are not flagged: they are data and work as they are.
Guides
- HTML vs JSX: every difference that breaks a pasteWhy class becomes className, how style, booleans, whitespace, braces, entities, forms, SVG and event handlers change, and what React 19 warns about.