DevToolBox

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

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の関数呼び出しに変換される構文糖衣です。そのためclassforのような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プロパティ
tabindextabIndexreadonlyreadOnly
maxlengthmaxLengthcolspancolSpan
rowspanrowSpancellpaddingcellPadding
contenteditablecontentEditablecrossorigincrossOrigin
autocompleteautoCompleteautofocusautoFocus
srcsetsrcSetnovalidatenoValidate

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-widthfill-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-linecapstrokeLinecapclip-pathclipPathstop-colorstopColortext-anchortextAnchorなどが同様にキャメルケース化が必要です。

8. 落とし穴7: イベントハンドラの値は文字列のまま

onclickonClickのように属性名はキャメルケース化されますが、値の"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 tagvoid要素などが閉じられていない/>で自己終了
Unexpected tokenHTMLコメントがそのまま残っている{/* */}形式に変換
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

関連ガイド / Related guides