コンソールの警告画面上は完璧に見えていても、Chromeのデベロッパーツールを開くと大量の警告が表示されることがあります。その中でも頻繁に見られるのが validateDOMNesting エラーです。通常、以下のようなメッセージで突然現れます。
Warning: validateDOMNesting(...): <div> cannot appear as a descendant of <p>.
See App > Layout > p > div.
アプリがクラッシュすることはありませんが、HTMLの基本ルールに違反しています。Reactは本質的に競合を指摘しています。ブラウザは段落(pタグ)の中にブロックレベル要素を配置することを許可していません。これを無視すると、ハイドレーションエラーや予期しないUIの崩れ(UI shifts)が発生し、ユーザーを困惑させる原因になります。
実際に何が起きているのかHTML5の仕様では、<p> 要素はテキストのコンテナとして定義されています。これには「フレーズ・コンテンツ(phrasing content)」、つまり <span>、<strong>、<em> などしか含めることができません。対照的に、<div> はブロックレベルの「フロー・コンテンツ(flow content)」です。ブラウザが <p> の中に <div> を見つけると、単に表示するだけでなく、<div> が始まる直前で段落を強制的に閉じます。これにより、Reactの仮想DOMとブラウザの実際の構造との間に不一致が生じます。
バグが発生する例このスニペットは、確実に警告を発生させる例です。
const MyComponent = () => {
return (
<p>
情報をチェックしてください:
<div>ここにブロックレベルのコンテンツが入ります</div>
</p>
);
};
なぜこのエラーが発生するのか- ライブラリのデフォルト設定: Material UI (MUI) などのUIキットでは、Typography コンポーネントがデフォルトで <p> としてレンダリングされることがよくあります。その中にリストやボックスをネストすると、警告が表示されます。- 動的な状態: ステータスメッセージや複雑なアイコンのラッパーを条件付きで表示する段落があるかもしれません。- CMSコンテンツ: dangerouslySetInnerHTML を使用して古いデータを挿入すると、単なるテキストだと思っていたコンテナの中に <div> が紛れ込むことがよくあります。## 手っ取り早い修正:コンテナを変更する最も速い解決策が最善である場合も多いです。SEOのためにどうしても段落が必要というわけでなければ、外側の <p> を <div> や <section> に入れ替えましょう。これにより、即座にHTML標準に準拠したコードになります。
// 汎用的なコンテナを使用して修正
const MyComponent = () => {
return (
<div>
情報をチェックしてください:
<div>ここにブロックレベルのコンテンツが入ります</div>
</div>
);
};
セマンティックな修正:Spanに切り替えるスタイリングのためにどうしても段落タグが必要な場合もあります。その場合は <p> を維持しつつ、すべての子要素がインライン要素であることを確認してください。内部の <div> を <span> に置き換え、ブロックのような見た目を維持する必要がある場合はCSSで display: block を適用します。
// ブロック形式のspanを使用した有効なHTMLネスト
const MyComponent = () => {
return (
<p>
情報をチェックしてください:
<span style={{ display: 'block' }}>
これで有効な形式になり、警告は発生しません
</span>
</p>
);
};

