2026年08月29日 01:15 / - PV

「デザイナーからもらったHTMLをReactコンポーネントにしたい」 「昔のサイトのパーツをNext.jsに移植したい」
そんなとき、HTMLをそのままJSXにコピペすると大量のエラーや警告に迎えられます。JSXはHTMLによく似ていますが、実体はJavaScriptの式なので、予約語や命名規則の衝突を避けるための書き換えルールがいくつも存在するからです。
本記事では、HTML→JSX移植で必要になる書き換えルールをまとめます。
先にお伝えすると、機械的に変換できる部分は手作業でやる必要はありません。弊社のWebツール集 Spoon Tools! に変換ツールがあります。
とはいえ、なぜその書き換えが必要なのかを知らないと変換後のコードを保守できないので、以下でルールを1つずつ解説していきます。
一番有名なやつです。classはJavaScriptの予約語(クラス宣言)なので使えません。
{/* HTML */}
<div class="container">
{/* JSX */}
<div className="container">
<label>のfor属性も、JavaScriptのfor文と衝突するためhtmlForになります。
<label htmlFor="email">メールアドレス</label>
ここが一番「手直し」感のあるポイントです。CSSプロパティ名はキャメルケースになり、値は文字列で渡します。
{/* HTML */}
<p style="font-size: 14px; background-color: #eee;">
{/* JSX */}
<p style={{ fontSize: '14px', backgroundColor: '#eee' }}>
{{ }}が二重なのは、「外側の{}=JSXの式埋め込み」+「内側の{}=オブジェクトリテラル」だからです。
HTMLでは閉じタグを省略できた<img>・<br>・<input>・<hr>・<meta>などは、JSXでは必ず/>で閉じます。閉じ忘れは構文エラーになります。
<img src="/logo.png" alt="ロゴ" />
<br />
<input type="text" name="email" />
{/* HTML */}
<button onclick="handleClick()">
{/* JSX */}
<button onClick={handleClick}>
onclick→onClickの名前変更に加えて、文字列ではなく関数そのものを渡す点が違います。onClick={handleClick()}と書くとレンダリング時に即実行されてしまうのも典型的なハマりどころです。
{/* HTML */}
{/* <!-- コメント --> は使えない */}
{/* JSXではこう書く */}
{/* コメント */}
JSXでvalueやcheckedを直接書くと「controlled component」として扱われ、onChangeとセットで書かないと入力できないフォームになります。初期値だけ与えたい場合はdefault〜を使います。
<input type="text" defaultValue="初期値" />
<input type="checkbox" defaultChecked />
tabindex → tabIndexreadonly → readOnlymaxlength → maxLengthautocomplete → autoCompletecolspan / rowspan → colSpan / rowSpanアイコンのSVGを直接JSXに貼るときに引っかかります。
stroke-width → strokeWidthfill-rule → fillRuleclip-path → clipPathxlink:href → xlinkHref数が多いので、SVGこそ手作業ではなく変換ツールに通すのがおすすめです。
CMSから返ってくるHTML文字列をそのまま表示したい場合はdangerouslySetInnerHTMLを使います。
<div dangerouslySetInnerHTML={{ __html: htmlString }} />
名前の通りXSSの危険があるので、信頼できない入力には必ずサニタイズを挟んでください。
HTML→JSXの書き換えは、要するに以下の3系統に整理できます。
機械的な変換はHTML→JSX変換ツールに任せて、controlled componentまわりなど「設計が絡む部分」だけ人間が判断する、という分担が効率的です。
この記事が何かのお役に立てれば幸いです。
最後までお読みいただきありがとうございました!
Share Me!