HTML Formatterhtmlformatteronline.com

HTML to JSX converter

Paste HTML and get JSX that compiles. Attributes renamed, inline styles turned into objects, every element closed, and anything that cannot be converted automatically is reported rather than guessed.

Your HTML 0 lines
Convert
JSX 0 lines
Paste HTML on the left, then press Convert.

What changes, and why

JSX looks like HTML and is not HTML. It compiles to JavaScript function calls, which means attribute names have to be valid JavaScript property names and every element has to be explicitly closed. Pasting raw HTML into a React component fails on all of that at once.

HTMLJSXBecause
classclassNameclass is a reserved word in JavaScript
forhtmlForSo is for
tabindextabIndexDOM properties are camelCase
style="color:red"style={{ color: 'red' }}JSX takes an object, not a string
<img src="a.jpg"><img src="a.jpg" />Every element must close
<!-- note -->{/* note */}HTML comments are not JSX syntax
disableddisabledBoolean attributes are already valid
onclick="fn()"removedJSX needs a function reference, not a string

Roughly sixty attributes get renamed, including the SVG ones — stroke-width becomes strokeWidth, clip-path becomes clipPath — which is the part people most often miss when converting an icon by hand.

Inline styles become objects

This is the conversion that takes longest by hand and the one most worth automating. Property names are camelCased, values become strings, and unitless numbers stay numbers.

HTML
<p style="color:#101b2d;font-weight:600;margin-top:12px">£58</p>
JSX
<p style={{ color: '#101b2d', fontWeight: 600, marginTop: '12px' }}>
  £58
</p>

Custom properties keep their dashes and get quoted, because --brand is not a valid JavaScript identifier: style={{ '--brand': '#3B4FE4' }}.

What it deliberately does not do

Three things are removed rather than guessed at, and each is listed underneath the panels when it happens.

Inline event handlers. onclick="addToCart(7)" is a string of JavaScript. JSX needs onClick={() => addToCart(7)} — a real function, in scope, in your component. Only you know where that function lives, so the attribute is dropped and the removal reported.

Script and style blocks. A <script> inside JSX does not run the way you expect, and a <style> block belongs in a stylesheet or a CSS-in-JS call. Both are removed with a note.

The doctype and document structure. A component returns an element, not a document. <!DOCTYPE> is dropped. <html> and <body> are kept if you paste them, but you almost certainly want to paste only the fragment you are turning into a component.

Component wrapper and fragments

With Wrap in a component ticked you get a complete file you can save and import. If your HTML has more than one top-level element, the output is wrapped in a fragment — <>...</> — because a React component must return a single node.

Ready to save as Card.jsx
export default function Component() {
  return (
    <div className="card" data-id="7">
      {/* product tile */}
      <img src="a.jpg" alt="Linen shirt" />
      <h3 className="title">Linen shirt</h3>
    </div>
  );
}

Untick it when you want a fragment to drop into a component you already have.

After the conversion

Four things to do by hand, in order of how often they bite:

  • Reattach event handlers. Every removed onclick, onsubmit and onchange needs a real function.
  • Make form fields controlled. React warns about value without onChange, and selected on an <option> should become value plus defaultValue on the <select>.
  • Rename to PascalCase if you want a component. A lowercase tag name compiles to a DOM element; only a capitalised one is treated as a component reference.
  • Check text containing braces. Literal { and } in text are escaped for you, but if you meant them as expressions you will want to rewrite them.

Does this work for Preact, Solid or Vue?

Preact — yes, entirely. It accepts both class and className, so the output works as-is.

Solid — mostly. Solid uses class rather than className and takes a style object like React does, so you will need to rename that one attribute back.

Vue — no. Vue templates are HTML, so you do not need converting at all. Paste your markup straight into a <template> block.

Svelte — no. Svelte components use plain HTML with class and string styles. Use your original markup.

Questions about this tool

Why was my onclick attribute removed?

Because JSX cannot use it. onclick="fn()" is a string that the browser evaluates; JSX needs onClick={{fn}}, a reference to a function that exists in your component's scope. There is no way to generate that automatically, so the attribute is dropped and the removal is listed under the panels.

Does it handle SVG?

Yes, and this is where it saves the most time. All the hyphenated SVG attributes — stroke-width, stroke-linecap, fill-rule, clip-path, stop-color — are camelCased, and self-closing tags are preserved. Converting an icon set by hand is exactly the job worth avoiding.

Can I convert a whole page?

You can, and you probably should not. A page is not a component. Convert the fragments — a card, a nav, a form — one at a time, which is how you would want to structure the React version anyway.

What about Tailwind classes?

They pass through untouched inside className. Tailwind works the same in JSX as in HTML; only the attribute name changes.

Is this the same as an HTML to React converter?

Same thing, different name. JSX is the syntax React uses, so converting HTML to JSX is converting it to React.

Related tools

Learn the why, not just the how

Longer reading on formatting, indentation and minification.