HTML to JSX 変換で必ずハマる7つの落とし穴
HTMLをそのままReactコンポーネントに貼り付けてビルドすると、Invalid DOM property 'class'. Did you mean 'className'?のようなエラーで止まった経験は多いはずです。JSXは見た目こそHTMLに似ていますが、実体は JavaScriptの関数呼び出しに変換される別の構文です。この記事ではhtml to jsx converterで検索する人が実際につまずく7つの落とし穴(class・for・style・自己終了タグ・ コメント・SVG属性・イベントハンドラ)を、変換前後のコードとReactの実際のエラーメッセージつきで 解説します。
Pasting raw HTML into a React component almost always fails to compile — Invalid DOM property 'class'. Did you mean 'className'? being the classic first error. JSX looks like HTML but compiles to JavaScript function calls, so a handful of mechanical rewrites are required every time. This guide walks through the seven pitfalls people hit most often, each with before/after code and the exact React error message it produces.
TL;DR
class→className、for→htmlForなど約30種類の属性名がHTMLとJSXで異なる- style文字列は使えない。
style={{ color: "red" }}のオブジェクト形式が必須 <img>/<br>/<input>などは自己終了させないとJSX構文エラーになる- HTMLコメント
<!-- -->は使えない。{/* */}に書き換える data-*・aria-*属性はHTMLのままでOK(変換不要)- 手作業が面倒なら HTML to JSX Converter に貼り付けるだけで機械的な変換が一括完了
HTML to JSX Converter
HTMLを貼り付けて変換ボタンを押すだけで、class→className・style文字列→オブジェクト・void要素の自己終了・HTMLコメント→JSXコメントを一括変換。tabindex→tabIndexなど約30種類の属性マッピングに対応。ブラウザ完結・外部送信なし。
今すぐ試す →1. なぜHTMLはそのままJSXにならないのか / Why HTML isn't valid JSX
JSXはトランスパイラによってJavaScriptの関数呼び出しに変換される構文糖衣です。そのためclassやforのようなJavaScriptの予約語と衝突する属性名は使えず、属性値は 単なる文字列ではなくJavaScript式として評価され、すべての要素は明示的に閉じられている必要があります。 「見た目はHTML、中身はJavaScript」という前提を押さえると、以降の7つの落とし穴がなぜ起きるのか 一気に理解できます。
JSX is syntactic sugar that a transpiler turns into JavaScript function calls. Attribute names that clash with JavaScript reserved words cannot be used as-is, attribute values are JavaScript expressions rather than plain strings, and every element must be explicitly closed. Keeping this in mind explains why each of the seven pitfalls below happens.
2. 落とし穴1: class → className
HTMLのclass属性はJavaScriptの予約語(class構文)と衝突するため、 JSXではclassNameを使います。
// Before (HTML)
<div class="card highlight">...</div>
// After (JSX)
<div className="card highlight">...</div>エラー: Invalid DOM property 'class'. Did you mean 'className'?
3. 落とし穴2: for → htmlFor
<label>のfor属性もJavaScript予約語のfor文と衝突するため、htmlForに変わります。同様の理由でHTMLとJSXの間で名前が変わる属性は約30種類あります。
// Before
<label for="email">Email</label>
// After
<label htmlFor="email">Email</label>代表的な属性名の対応は次のとおりです。
| HTML属性 | JSXプロパティ | HTML属性 | JSXプロパティ |
|---|---|---|---|
tabindex | tabIndex | readonly | readOnly |
maxlength | maxLength | colspan | colSpan |
rowspan | rowSpan | cellpadding | cellPadding |
contenteditable | contentEditable | crossorigin | crossOrigin |
autocomplete | autoComplete | autofocus | autoFocus |
srcset | srcSet | novalidate | noValidate |
Around 30 HTML attributes are renamed to their DOM property form in JSX. class and for are the two everyone hits first because they collide with JavaScript keywords.
4. 落とし穴3: style属性の書き方の違い
HTMLのstyleは「プロパティ:値;」のCSS文字列ですが、JSXのstyleは JavaScriptオブジェクトです。プロパティ名はキャメルケースになり、px単位の数値はクォート無しの 数値として書けます。
// Before
<h1 style="color: red; font-size: 24px; margin-top: 8px;">Hello</h1>
// After
<h1 style={{ color: "red", fontSize: 24, marginTop: 8 }}>Hello</h1>エラー: The 'style' prop expects a mapping from style properties to values, not a string.
5. 落とし穴4: 自己終了タグ必須化(void要素)
HTMLでは<img> / <br> / <hr> /<input> / <meta>などの「void要素」は閉じタグを書きません(あるいは 省略可能)。しかしJSXにはHTMLのような「閉じタグ省略」の仕組みが一切無く、子要素を持たない要素は<img ... />のようにスラッシュで自己終了させる必要があります。
// Before
<img src="photo.jpg" alt="Photo">
<br>
<input type="text">
// After
<img src="photo.jpg" alt="Photo" />
<br />
<input type="text" />エラー: Expected corresponding JSX closing tag for <img>.void要素だけでなく、HTMLの寛容なパーサーに甘えて<p>の閉じタグを省略しているような 古いマークアップも同様にエラーになります。
6. 落とし穴5: コメントの書き方
HTMLコメント<!-- -->はJSXの構文として無効です。波括弧で囲んだ{/* ... */}という「JS式としてのコメント」に置き換える必要があります。
// Before
<!-- 送信ボタン -->
<button>Submit</button>
// After
{/* 送信ボタン */}
<button>Submit</button>エラー: Unexpected token(コメントの直後の位置で発生することが多い)
7. 落とし穴6: SVG属性のcamelCase化
SVGをインラインでJSXに貼り付けると、stroke-widthやfill-ruleのような ケバブケースの属性名がエラーになります。HTML属性の変換ロジック(class・for・void要素など)は SVG特有の属性名までは対応しないことが多く、手動での書き換えが必要になりがちな落とし穴です。
// Before
<svg viewBox="0 0 24 24">
<path stroke-width="2" fill-rule="evenodd" d="..." />
</svg>
// After
<svg viewBox="0 0 24 24">
<path strokeWidth="2" fillRule="evenodd" d="..." />
</svg>エラー: Invalid DOM property 'stroke-width'. Did you mean 'strokeWidth'?
他にもstroke-linecap→strokeLinecap、clip-path→clipPath、stop-color→stopColor、text-anchor→textAnchorなどが同様にキャメルケース化が必要です。
8. 落とし穴7: イベントハンドラの値は文字列のまま
onclick→onClickのように属性名はキャメルケース化されますが、値の"handleClick()"という文字列自体は関数参照には変換されません。7つの中で 唯一、機械的な変換だけでは完結しない落とし穴です。
// Before
<button onclick="handleClick()">Submit</button>
// 属性名だけ変換された直後(まだ動かない)
<button onClick="handleClick()">Submit</button>
// 手動修正が必要
<button onClick={handleClick}>Submit</button>JSXのonClickは関数参照(または() => ...のインラインアロー関数)を 受け取ります。文字列のままだとクリックしても何も起こりません。
9. 変換後によく出るエラーメッセージ一覧 / Common errors after conversion
| エラー | 原因 | 対処 |
|---|---|---|
Invalid DOM property 'class' | classがそのまま残っている | classNameに置換 |
The 'style' prop expects a mapping... | style属性が文字列のまま | オブジェクト形式に変換 |
Expected corresponding JSX closing tag | void要素などが閉じられていない | />で自己終了 |
Unexpected token | HTMLコメントがそのまま残っている | {/* */}形式に変換 |
Invalid DOM property 'stroke-width' | SVG属性がケバブケースのまま | strokeWidth等に手動修正 |
Adjacent JSX elements must be wrapped... | 変換結果のルート要素が複数ある | <>...</>で全体を包む |
10. data-* と aria-* はそのまま使える
唯一「変換しなくていい」属性がdata-*とaria-*です。これらはReactでも HTMLと同じ名前のまま有効なDOMプロパティとして扱われるため、data-user-id="42"やaria-label="閉じる"はJSXでもそのまま書けます。「全部キャメルケースに しなきゃ」と思い込んで書き換えてしまうと、ブラウザが属性を認識できなくなり逆に壊れます。
data-* and aria-* attributes are the one exception to all the renaming rules above — React keeps them exactly as written, so leave them alone.
まとめ / Summary
7つの落とし穴はどれも「JSXはHTMLではなくJavaScript」という一点に集約されます。class・for・style・ 自己終了タグ・コメント・SVG属性の6つは機械的なルールなので、HTML to JSX Converterに貼り付ければ 一括変換できます。残るイベントハンドラの関数参照化だけは、コンポーネントの設計に依存するため 手作業で仕上げてください。
Converting HTML to JSX always trips up the same handful of things: class becomes className, for becomes htmlFor (plus roughly 30 other attributes such as tabindex, readonly and colspan), inline style strings become camelCased objects, void elements like img and br must be self-closed, HTML comments become curly-brace JS comments, and SVG-specific kebab-case attributes such as stroke-width must be renamed to strokeWidth by hand. data-* and aria-* attributes are the one exception — they stay exactly as written. All of the mechanical rewrites can be automated with a converter tool, but event handler values remain strings after conversion (onClick="handleClick()") and must be rewritten as function references (onClick={handleClick}) manually, since that depends on how your component defines its functions.
HTML to JSX Converter
class→className・style文字列→オブジェクト・void要素の自己終了・コメント変換を一括処理。残るのはイベントハンドラの関数参照化だけです。ブラウザ完結・外部送信なし。
今すぐ試す →関連ツール / Related tools
- HTML to JSX Converter — HTMLをReact JSXに一括変換
- HTML Formatter & Minifier — 変換前にHTMLを整形
- JSON to TypeScript — props/state の型定義を生成