1. Home
  2. Developer tools
  3. HTML to JSX

HTML to JSX

Bring a template, a design-tool export or a snippet from documentation into a React app without fixing every attribute by hand.

Free, no sign-up. Runs in your browser: nothing is uploaded.

How to use HTML to JSX

  1. Paste HTML.
  2. Name the component and choose TypeScript or JavaScript.
  3. Copy or download the component.

Features

  • className, htmlFor, tabIndex, readOnly and 35 more attribute renames
  • style="…" to a style object, px numbers unwrapped
  • Void elements closed: <img />, <input />, <br />
  • SVG attributes camelCased: stroke-width → strokeWidth
  • Fragment wrapper when there are several root elements

Supported formats

Input

  • HTML

You get

  • TSX
  • JSX

Private by design

Everything you enter is processed by your browser on this device. Nothing is sent to openWorkstand or anyone else, so the HTML to JSX is safe for private and work data. After you have used it once while online, it also works without an internet connection. How local processing works

Good to know

  • Inline event handlers become empty function stubs; move their code into React handlers.
  • Inline <script> elements are kept as text and will not run.

Guide

Converting HTML into React JSX without breaking it

JSX looks like HTML, which is why pasting markup into a React component feels as if it should just work. It does not: JSX is JavaScript, so attribute names, inline styles, comments, closing tags and even curly braces in text follow different rules, and a single difference stops the build. This converter rewrites HTML into a JSX or TSX component and points out the parts that need a human decision.

Attribute names

Some HTML attributes clash with JavaScript keywords or follow DOM property names in React. class becomes className, for becomes htmlFor, and multi-word attributes take camelCase: tabindex → tabIndex, readonly → readOnly, maxlength → maxLength, srcset → srcSet, crossorigin → crossOrigin. The converter knows 39 of these renames. data- and aria- attributes keep their hyphens, as React expects. Other hyphenated attributes, which are mostly SVG presentation attributes, are camelCased: stroke-width becomes strokeWidth and fill-rule becomes fillRule.

Inline styles become objects

In JSX, style takes an object, not a string. style="max-width: 420px; margin: 0 auto; padding: 24px" becomes style={{ maxWidth: 420, margin: '0 auto', padding: 24 }}: property names are camelCased, pixel values become plain numbers (React adds px), and other values stay strings. Unitless properties such as line-height, z-index and opacity keep their numbers as they are, and custom properties such as --gap keep their names in quotes.

Tags, text and comments

Every element must be closed in JSX, so void elements such as <input>, <img> and <br> become self-closing. JSX also needs a single root, so the output is wrapped in a fragment <>…</> when the markup has several top-level elements or loose text. Curly braces in text would start JavaScript expressions, so they are escaped as {'{'} and {'}'}. HTML comments become JSX comments, {/* … */}.

Form fields and event handlers

In React, an input with a value becomes controlled and cannot be typed into without state. To keep the behaviour of the original HTML, value and checked on form fields are converted to defaultValue and defaultChecked. Inline handlers such as onclick="track('signup')" cannot run as strings, so they become onClick={() => { /* track('signup') */ }} with a warning, leaving you to move the code into a real function.

A worked example

The Sample is a sign-up card. The output starts with export default function SignupCard(): JSX.Element {, keeps the comment as {/* Sign-up card */}, and turns the wrapper into <div className="card" style={{ maxWidth: 420, margin: '0 auto', padding: 24 }}>. The label becomes <label htmlFor="email">Email</label>, the email input ends with autoFocus />, the SVG keeps strokeWidth="2" fillRule="evenodd", and the text “Prices in {currency}” becomes Prices in {'{'}currency{'}'} so React does not treat it as a variable. One warning explains the onclick stub.

What still needs attention

Inline <script> elements are kept as text with a warning, because React does not execute scripts inserted this way; load them with useEffect or your framework’s script helper. Repeated markup is a candidate for map() over data, and hard-coded text is a candidate for props. Very malformed HTML, such as unclosed tags, produces a warning listing the unclosed elements; fix those in the source first.

Checked against the current version of the HTML to JSX on .

Frequently asked questions

Why does React warn about a missing key after I paste a list?

The converter produces static JSX, and static lists need no keys. The warning appears once you turn repeated items into an array with map(); give each item a stable key from its data, such as an id, rather than its index.

Can I keep using class instead of className?

React itself requires className in JSX and prints a warning for class. Preact accepts both, and some compilers such as Solid use class, so if you target one of those, a find-and-replace after converting is enough.

Why did value become defaultValue?

In React, value on an input makes it controlled: it can no longer be typed into unless you add state and onChange. defaultValue keeps the HTML behaviour, where the value is only the starting text.

What happens to onclick attributes?

They become onClick handlers containing a comment with the original code. Inline strings cannot run in React, so move the code into a function and pass it to onClick.

Keep working with the result

openWorkstand also includes a free workspace with documents, spreadsheets, tasks, projects and a calendar that save to a folder on your computer.