HTMLをReactコンポーネントに貼り付けると、ほぼ確実にエラーが発生します。classは構文エラーになり、インラインスタイルはフォーマットが合わず、自己終了スラッシュがない空要素はパーサーを壊します。HTMLからJSXへの変換は機械的ですが、ミスが起きやすい作業です。このガイドでは全ての変換ルールを体系的に解説します。手作業を省きたい場合はHTML to JSXコンバーターを使ってください。
HTMLとJSXが異なる理由
JSXはHTMLに見えますが、React.createElement()呼び出しにコンパイルされます。JSXはJavaScriptの中に存在するため、一部のHTML属性はJSの予約語と衝突し、その他の属性はHTML規約ではなくJavaScriptの命名規約に従います。
違いは主に5つのカテゴリに分けられます:
- 予約語のリネーム —
class→className、for→htmlFor - camelCase属性名 —
onclick→onClick、tabindex→tabIndex - インラインスタイルのオブジェクト化 —
style="color:red"→style={{ color: 'red' }} - 空要素の自己終了 —
<br>→<br />、<img src="...">→<img src="..." /> - コメント構文の変化 —
<!-- ... -->→{/* ... */}
属性変換対照表
| HTML | JSX | 理由 |
|---|---|---|
class="btn" | className="btn" | classはJS予約語 |
for="email" | htmlFor="email" | forはJS予約語 |
onclick="fn()" | onClick={fn} | JSイベント命名規則 |
onchange={...} | onChange={...} | camelCase |
tabindex="0" | tabIndex={0} | camelCase |
readonly | readOnly | camelCase |
maxlength="10" | maxLength={10} | camelCase |
colspan="2" | colSpan={2} | camelCase |
rowspan="3" | rowSpan={3} | camelCase |
crossorigin | crossOrigin | camelCase |
contenteditable | contentEditable | camelCase |
<br> | <br /> | JSXは明示的な閉じタグが必要 |
<img src="..."> | <img src="..." /> | JSXは明示的な閉じタグが必要 |
<input type="text"> | <input type="text" /> | JSXは明示的な閉じタグが必要 |
<!-- コメント --> | {/* コメント */} | JSX式の中のJSブロックコメント |
インラインスタイル
最も混乱しやすい点です。HTMLのインラインスタイルは文字列ですが、JSXのインラインスタイルはJavaScriptオブジェクトです。
<!-- HTML -->
<div style="color: red; font-size: 14px; background-color: #fff;"></div>
// JSX
<div style={{ color: 'red', fontSize: '14px', backgroundColor: '#fff' }}></div>
3つのルールがあります:
- 値は文字列ではなくオブジェクト(二重の波括弧:外側はJSX式、内側はオブジェクトリテラル)。
- プロパティ名はcamelCase(
font-size→fontSize、background-color→backgroundColor)。 opacityやzIndexのような単位なし数値はそのまま数値で書けます。ピクセル値は文字列('14px')が必要です。
空要素の自己終了
HTML5では、<br>・<hr>・<img>・<input>・<link>・<meta>などの空要素は閉じタグ不要です。しかしJSXでは明示的な自己終了が必須です:
<!-- HTML — 有効 -->
<img src="photo.jpg" alt="写真">
<br>
<input type="text" name="email">
<hr>
// JSX — 必須
<img src="photo.jpg" alt="写真" />
<br />
<input type="text" name="email" />
<hr />
コメント
HTMLコメントはパーサーが無視し、DOMには現れません。JSXのコメントはJavaScript式でラップする必要があります:
<!-- HTMLコメント -->
<p>コンテンツ</p>
{/* JSXコメント */}
<p>コンテンツ</p>
よくある移行シナリオ
静的HTMLテンプレートをReactコンポーネントに移行する
完全なHTMLドキュメントから外側の構造を取り除きます:
<!-- HTML -->
<div class="container">
<header class="header">
<nav>
<a href="/" class="logo">ブランド</a>
<ul class="nav-list">
<li><a href="/about">About</a></li>
</ul>
</nav>
</header>
</div>
// Reactコンポーネント
export function Layout() {
return (
<div className="container">
<header className="header">
<nav>
<a href="/" className="logo">ブランド</a>
<ul className="nav-list">
<li><a href="/about">About</a></li>
</ul>
</nav>
</header>
</div>
);
}
FigmaやWebflowからのコピー
デザインツールは通常classベースのHTMLをエクスポートします。変換は単純で、classをclassNameに全置換し、イベント属性をcamelCaseにして、空要素に自己終了スラッシュを追加するだけです。
メールHTMLをReact Emailに変換する
メールHTMLはテーブルレイアウトと大量のインラインスタイルで構成されていることが多いです。主な作業はインラインスタイルの変換で、すべてのstyle="..."文字列をstyle={{ ... }}オブジェクトに書き換えます。変換後はreact-emailやjsx-emailでそのまま使えます。
よくある落とし穴
Boolean属性 — HTMLではdisabled・checked・selectedは裸の属性です。JSXではdisabled={true}または省略形のdisabledを使います。コンバーターはどちらの形式も自動処理します。
data-*とaria-*属性 — これらはJSXでもハイフン区切りのままです。data-testid="btn"とaria-label="閉じる"はcamelCaseにしません。
SVG属性 — SVGには独自の属性命名ルールがあります。viewBoxはJSXでcamelCaseのまま使用し、stroke-widthはstrokeWidthに変換されます。SVGの変換が目的なら、SVG to JSXコンバーターがこれらのルールを正しく処理します。
数値属性 — HTMLではtabindex="0"は文字列です。JSXでは数値形式tabIndex={0}が推奨されます。ほとんどのコンバーターが自動で処理します。
オンラインHTML to JSXコンバーター
ZeroToolのHTML to JSXコンバーターは、上記のすべてのルールをブラウザ内で即座に適用します。任意のHTMLスニペットを貼り付けると、有効なJSX出力がすぐに得られます。サーバー不要・サインアップ不要・データ送信なし。