Fixing React validateDOMNesting: Stop Putting <div> Inside <p>

beginner⚛️ React2026-04-24| React 16.8+, Next.js (Client-side rendering), Chrome DevTools

Error Message

Warning: validateDOMNesting(...): <div> cannot appear as a descendant of <p>. See ... > p > div.
#react#dom#html#nesting#validateDOMNesting#semantic-html

The Warning in Your ConsoleEverything looks perfect on your screen until you open the Chrome DevTools and hit a wall of yellow warnings. Among the most frequent is the validateDOMNesting error. It usually catches you off guard with a message like this:

Warning: validateDOMNesting(...): <div> cannot appear as a descendant of <p>. 
See App > Layout > p > div.

Your app won't crash, but you are breaking core HTML rules. React is essentially flagging a conflict: browsers don't allow block-level elements inside paragraphs. Ignoring this often triggers hydration errors or unpredictable UI shifts that can frustrate users.

What's Actually HappeningThe HTML5 specification defines a <p> element as a container for text. It only accepts "phrasing content"—think <span>, <strong>, or <em>. In contrast, a <div> is "flow content," which is block-level. When a browser finds a <div> inside a <p>, it doesn't just display it. It forces the paragraph to close early, right before the <div> begins. This creates a mismatch between React's virtual DOM and the browser's actual structure.

Where the Bug LivesThis snippet is a guaranteed way to trigger the warning:

const MyComponent = () => {
  return (
    <p>
      Check out this info:
      <div>Some block-level content here</div>
    </p>
  );
};

Why This Error Pops Up- Library Defaults: UI kits like Material UI (MUI) often use a Typography component that renders as a <p> by default. If you nest a list or a box inside it, the console will scream.- Dynamic States: You might have a paragraph that conditionally shows a status message or a complex icon wrapper.- CMS Content: Using dangerouslySetInnerHTML to inject legacy data can easily sneak a <div> into a container you assumed was just text.## The Quick Fix: Change the ContainerThe fastest solution is often the best. If you don't strictly need a paragraph for SEO, swap the outer <p> for a <div> or a <section>. This instantly aligns your code with HTML standards.

// Fixed by using a generic container
const MyComponent = () => {
  return (
    <div>
      Check out this info:
      <div>Some block-level content here</div>
    </div>
  );
};

The Semantic Fix: Switch to SpansSometimes you need that paragraph tag for styling. In that case, keep the <p> but ensure all children are inline. Replace the inner <div> with a <span> and apply display: block in your CSS if you need it to keep its block-like appearance.

// Valid HTML nesting with block-styled spans
const MyComponent = () => {
  return (
    <p>
      Check out this info:
      <span style={{ display: 'block' }}>
        This is now valid and won't trigger warnings
      </span>
    </p>
  );
};

Next.js and the Hydration NightmareSSR frameworks like Next.js make this error particularly dangerous. During the initial server render, React generates a string where the div is inside the p. However, the moment that HTML hits the browser, the browser "corrects" it. When React tries to take over on the client, the DOM it sees doesn't match the one it sent. This leads to the dreaded "Hydration Mismatch," which can cause slow page loads or even 0.5s layout jumps while the browser struggles to reconcile the two versions.

Verification Checklist- Save your file and let the Hot Module Replacement (HMR) update the page.- Press F12 to open the console and perform a hard refresh.- Confirm the validateDOMNesting warning has vanished.- Right-click the element and select Inspect. Verify that the browser isn't injecting ghost closing tags (</p><p>) around your content.### Quick Reference: Valid Nesting- <p> Accepts: <span>, <a>, <button>, <strong>, <br>.- <p> Rejects: <div>, <h1-h6>, <ul>, <section>, <p>.

Related Error Notes