HTML → JSX / React 转换器,免费

自动将 HTML 转换为兼容 React 的 JSX。处理 class→className、for→htmlFor、style 对象、事件处理、自闭合标签等。

输入与输出

选项

工作原理

  1. 粘贴 HTML:在输入区输入标准 HTML 片段 · div、表单、表格或完整代码块。
  2. 选择选项:按需启用 React Fragment 包裹和美化输出。
  3. 立即获得 JSX:转换器会自动将 class 转为 classNamefor 转为 htmlFor,将 style 字符串转为 style 对象,并闭合自闭合标签。
  4. 复制到项目中:将 JSX 输出直接粘贴到您的 React 组件中。

为什么使用 HTML → JSX?

将 HTML 模板迁移到 React 时,手动转换容易出错。忘记一个 className 或留下未闭合的标签都会导致构建失败。此转换器自动处理所有必要变更 · 包括将 style 属性中 background-color 等 CSS 属性名转为驼峰的 backgroundColor、将事件处理器字符串转为函数引用,以及正确闭合 void 元素。这能加速原型设计、代码迁移,并帮助不熟悉 JSX 语法差异的开发者。

关键转换

  • class → className · React 组件中必需
  • for → htmlFor · 用于 label 元素
  • style 字符串 → 对象 · 例如 "color:red"{color:'red'}
  • 自闭合标签 · <br><br />
  • Fragment 包裹 · 可选的外部 <>…</>

What JSX actually is

JSX stands for "JavaScript XML." It's a syntactic extension to JavaScript invented by Jordan Walke at Facebook in 2013 as part of the original React announcement at JSConf US. JSX lets you write XML-like markup directly inside JavaScript code, <div className="hello">World</div>: and a transpiler (today almost always Babel) compiles it to plain function calls: React.createElement('div', {className: 'hello'}, 'World'). The browser never sees JSX directly; what ships is regular JavaScript.

Walke's original motivation was that template languages (Mustache, Handlebars, Angular's old directives) were second-class citizens of the host language, they couldn't use JavaScript's loops, conditionals or variables natively, so each one reinvented its own. JSX inverted the relationship: instead of templates that occasionally do JavaScript, it gave you JavaScript that occasionally does markup. The fact that {condition && <Item />} is a normal JS expression that returns a React element is the load-bearing idea.

Since React 17 (October 2020), the automatic JSX runtime means you no longer have to import React from 'react' in every file that uses JSX, Babel inserts the runtime imports automatically. JSX has also been adopted well beyond React itself: Preact, Solid, Qwik, Hono JSX, Million, Lit, and TypeScript's .tsx all consume the same syntax. The JSX draft spec at facebook.github.io/jsx is intentionally framework-agnostic.

The full list of HTML→JSX differences

  • Reserved word renames. classclassName (because class is reserved in JS). forhtmlFor (same reason, for is the loop keyword). These are the two everyone gets bitten by first.
  • All other attributes are camelCased. tabindextabIndex, readonlyreadOnly, maxlengthmaxLength, contenteditablecontentEditable.
  • Two important exceptions stay kebab-case. aria-* attributes (aria-label, aria-hidden) and data-* attributes (data-testid) keep their HTML form. Same for xmlns.
  • Self-closing tags are mandatory for void elements: <br> becomes <br />, <img> becomes <img />, <input> becomes <input />. JSX is XML-strict where HTML is forgiving.
  • Inline styles take an object, not a string. style="color: red; background-color: blue" becomes style={{ color: 'red', backgroundColor: 'blue' }}. Note three things: double curly braces (one for the JSX expression, one for the object literal), camelCase property names, string values quoted. Numeric pixel values omit the unit: marginTop: 16, not '16px'.
  • Event handlers are camelCased and take function references. onclick="handleClick()" becomes onClick={handleClick}: note the missing parentheses. onClick={handleClick()} would call handleClick at render time and assign its return value as the handler, which is almost always a bug.
  • Comments use {/* … */} inside JSX, not <!-- … -->. The HTML comment syntax has no meaning inside JSX.
  • Fragments wrap multiple siblings. A component must return a single root, so multiple top-level elements need <>…</> (or the longer <React.Fragment>…</React.Fragment>) wrapped around them.
  • Conditional rendering uses JS expressions. {isVisible && <Item />} renders the item only if the condition is truthy; {condition ? <A /> : <B />} picks one of two.
  • Curly braces in text need escaping. The literal { inside JSX text content is interpreted as the start of an expression. Use {'{'} or an HTML entity equivalent.

SVG, accessibility, and the rest

SVG works inside JSX with the same camelCase rule for most attributes, viewBox, strokeWidth, fillOpacity. The notable exceptions: xlink:href uses the special xlinkHref spelling (now deprecated in favour of plain href), and xmlns stays as is. Accessibility attributes follow ARIA's own kebab-case convention by exception: aria-label, aria-describedby, role all stay as written.

For CSS, JSX's inline style object is one option. Most production codebases use one of three richer alternatives: CSS Modules (per-file scoped class names compiled by the bundler), Tailwind CSS (utility classes that pass through cleanly via className), or CSS-in-JS libraries like styled-components, Emotion or Vanilla Extract. Tailwind has become the most common choice in new projects since 2022; Tailwind classes need no conversion at all when moving HTML to JSX, they pass through as ordinary className strings.

Common conversion gotchas

  • Inline event handlers that call the function. onclick="alert(1)" in HTML usually becomes onClick={() => alert(1)} in JSX, wrapped in an arrow function so the alert fires on click, not on render. A naive converter that produces onClick={alert(1)} will pop the alert at render time rather than when the user clicks. This converter handles the common cases but worth eyeballing the output.
  • HTML comments get dropped. Most JSX converters strip HTML comments rather than translating them to {/* */} form, because the latter only works in specific positions inside JSX. Add comments back manually where you want them.
  • SVG attribute renames aren't always handled by automated converters. stroke-width, fill-rule, clip-path, text-anchor all need camelCase forms, check the output carefully if you're pasting SVG from an icon set like Heroicons or Lucide.
  • Boolean attributes. <input disabled> in HTML becomes <input disabled /> in JSX. <input disabled="false"> in HTML is actually disabled (any value enables it), but in JSX disabled={false} is correctly off, the JSX semantic is more sensible than the HTML one.
  • HTML entities. &copy; works in JSX text content but using the literal Unicode character (©) is preferred. &nbsp; works the same.
  • The tabindex case. Should be tabIndex. Easy to forget because the value is often 0 or -1 and looks numeric, but the attribute name still needs camelCase.

When you'd reach for this

  • Migrating server-rendered templates to React. Pasting a chunk of an existing site's HTML and getting JSX out is the canonical use case.
  • Pulling in icons, badges, or design-tool exports. Heroicons, Lucide, Figma's "Copy as SVG" all give you raw HTML/SVG that needs the rename pass.
  • Converting Tailwind UI / Flowbite / DaisyUI snippets from their HTML examples to JSX for a React project. The Tailwind classes pass through unchanged; only the structural attributes need conversion.
  • Onboarding developers who know HTML but not JSX: seeing the mechanical rules applied automatically is faster than reading a list of differences.
  • Quick prototyping when you've drafted markup in plain HTML for sketching purposes and want it inside a React component.

The output works for any JSX consumer, React, Preact, Solid, Qwik, Hono JSX, Million, Lit's html template literal (with minor adjustments). It does not work for React Native, which uses native primitive components like <View> and <Text> rather than HTML elements.

More questions

What's the difference between JSX and HTML?

HTML is a markup language the browser parses directly. JSX is a JavaScript expression syntax that compiles to React.createElement calls, it never reaches the browser as JSX. JSX looks XML-strict (every tag must close, attributes use camelCase) because it's parsed as JavaScript expressions, not as forgiving HTML. The visual similarity is intentional but the underlying semantics are quite different.

Do I still need to import React in every JSX file?

Not since React 17 (October 2020), which introduced the automatic JSX runtime. With it, Babel injects the necessary runtime imports for you, so files that only use JSX don't need a top-of-file import React from 'react'. The classic runtime is still available for older toolchains. Most new projects use the automatic runtime.

Can I use JSX without React?

Yes. JSX is a generic syntax with a draft spec at facebook.github.io/jsx, and many frameworks consume it: Preact, Solid, Qwik, Hono JSX, Million, Lit, and the htm tagged-template variant. The frameworks differ in what JSX compiles to (Preact uses h(…), Solid compiles to fine-grained reactive primitives, etc.) but the syntax is shared.

Why does style take an object instead of a string?

Because the JSX expression syntax already provides curly braces for embedding JavaScript values, and an object literal is the most natural JS representation of a property bag. The style object also allows numbers (most automatically get px) and JS expressions, which a string can't. The trade-off is the slightly awkward double-brace style={{ … }} syntax, outer braces for "this is a JSX expression," inner braces for the object literal.

Does anything get sent to a server?

No. The conversion logic is pure JavaScript that walks your HTML string and rewrites attributes, all in your browser. The HTML you paste never leaves the page, useful when migrating proprietary internal templates or component markup with API endpoints baked in.