How to Fix: The element `nextjs-portal` affects other elements on the site

6 min read

The nextjs-portal element is not harmless in development, and when global CSS targets it, the entire page layout can shift, overlay, or inherit unexpected behavior.

This issue shows up most often in a Next.js app running in development mode, where Next injects internal UI through a custom element named nextjs-portal. If your reset, wildcard selectors, positioning rules, stacking context rules, or theme CSS accidentally style that element, the portal can start affecting unrelated parts of the page.

Understanding the Root Cause

In Next.js development, the framework mounts internal overlays and diagnostics into a custom DOM node called nextjs-portal. This element is used by the dev overlay and related tooling. Under normal conditions, it should stay isolated. The problem begins when application CSS includes selectors that match all elements, unknown custom elements, or broad layout containers.

Typical examples include:

  • * { ... } applying layout or visual rules globally
  • body > * { ... } affecting every direct child in the document
  • div, section, main, ... style patterns later expanded to custom elements indirectly
  • position, transform, filter, z-index, or overflow rules that create a new stacking context
  • Global resets that assign margins, display modes, or font/layout properties to everything

Because nextjs-portal exists in the real DOM, it can receive those styles like any other element. Once that happens, several side effects are possible:

  • The portal may take up space in normal document flow
  • It may overlay content unexpectedly
  • It may inherit positioning that breaks click behavior
  • It may create scrollbars or clipping issues
  • It may affect siblings if parent-level selectors are broad enough

So the root cause is not that Next.js randomly breaks layout. The root cause is that development-only framework elements are being styled by app-level global CSS.

This is also why the bug is usually reproducible only in development and not in production: the dev overlay infrastructure differs between environments.

Step-by-Step Solution

The safest fix is to isolate your app styles so they do not target nextjs-portal or other framework-owned nodes.

1. Audit your global CSS

Search your codebase for selectors that are overly broad. Pay special attention to files like globals.css, reset stylesheets, layout wrappers, and theme providers.

* {
  box-sizing: border-box;
}

body > * {
  margin: 0;
}

body * {
  font-family: inherit;
}

Selectors like these are not always wrong, but they become risky when they control layout, positioning, overflow, or rendering behavior.

2. Scope styles to your application root

Instead of styling every element in the document, wrap your actual app UI in a dedicated container and scope global rules to that container only.

For example, in the App Router:

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body>
        <div id="app-root">{children}</div>
      </body>
    </html>
  )
}

Then update CSS:

#app-root * {
  box-sizing: border-box;
}

#app-root {
  min-height: 100vh;
}

#app-root > * {
  margin: 0;
}

This prevents nextjs-portal from being unintentionally styled, because it sits outside your app container.

3. Avoid layout rules on universal selectors

Universal selectors are acceptable for limited resets, but avoid applying structural rules globally.

Problematic:

* {
  position: relative;
  overflow: hidden;
}

Safer:

* {
  box-sizing: border-box;
}

body {
  margin: 0;
}

Rules like position: relative, overflow: hidden, display: flex, and custom transforms should be attached only to known application components.

4. Explicitly neutralize nextjs-portal if needed

If a third-party stylesheet or legacy reset is difficult to untangle, you can defensively reset the portal element in development-facing CSS.

nextjs-portal {
  all: initial;
}

Use this carefully. The all property is powerful and may interfere with Next’s own overlay rendering if overused. In many cases, a gentler reset is better:

nextjs-portal {
  box-sizing: content-box;
  margin: 0;
  padding: 0;
  border: 0;
}

This should be treated as a fallback, not the first fix. The best long-term solution is still proper CSS scoping.

5. Inspect the element in DevTools

Open browser DevTools while running the reproduction in development. Select nextjs-portal and inspect the Computed and Styles tabs. This will show exactly which selector is leaking into the element.

Look for:

  • display changes
  • position changes
  • inset, top, left
  • z-index
  • font, line-height, color
  • overflow or clipping

Once you find the offending rule, move it behind a scoped container or replace it with a more targeted selector.

6. Verify behavior in both development and production

After the CSS changes:

npm install
npm run dev

Then test the production build as well:

npm run build
npm start

This confirms that your fix removes the development issue without breaking the production UI.

Example of a clean scoped setup

/* globals.css */
html, body {
  margin: 0;
  padding: 0;
}

* {
  box-sizing: border-box;
}

#app-root {
  min-height: 100vh;
}

#app-root .page {
  display: flex;
  flex-direction: column;
}

#app-root .layout {
  position: relative;
}
export default function Page() {
  return (
    <main className="page">
      <section className="layout">
        <h1>Hello</h1>
      </section>
    </main>
  )
}

This pattern keeps framework-owned nodes outside the blast radius of your app-specific styling.

Common Edge Cases

1. CSS reset libraries that target everything

Some reset packages or hand-written resets include aggressive defaults. If they apply structural rules globally, they can still affect nextjs-portal. Review imported CSS, not just your own files.

2. Styled-components, Emotion, or CSS-in-JS global blocks

If you use a global style injection helper, the same problem can happen there. Broad selectors inside createGlobalStyle or equivalent APIs should be scoped just like plain CSS.

3. Tailwind base layer customizations

Tailwind itself is usually fine, but custom rules inside @layer base can accidentally style framework elements. Be careful with selectors like *, :root, body > *, or generic element-wide overrides.

4. Overflow and scroll bugs

If you set overflow: hidden or height: 100% globally, the portal can contribute to clipping, scrolling anomalies, or hidden overlays. These issues are easy to misdiagnose as router or rendering bugs.

5. Z-index conflicts

When the portal inherits a stacking rule, the dev overlay may appear behind the app or in front of interactive UI unexpectedly. If you see invisible click blockers, inspect stacking contexts first.

6. Hydration confusion

Developers sometimes suspect a hydration mismatch because the page looks different after startup. In this case, the real issue is often CSS being applied differently once the development portal is mounted.

FAQ

Why does this happen only in development?

Because nextjs-portal is part of Next.js development tooling. Production builds do not use the same developer overlay structure, so the element may not exist there at all.

Can I safely hide nextjs-portal with CSS?

No, that is usually a bad idea. Hiding it can break the Next.js error overlay and debugging experience. The right fix is to stop your application CSS from unintentionally styling it.

What is the best long-term fix?

The best fix is to scope global styles to a dedicated app root and avoid applying layout-related rules through universal or document-wide selectors. That keeps framework internals isolated and makes your CSS more predictable.

If you want to inspect the original reproduction, open the repository on GitHub. The key takeaway is simple: treat framework-injected DOM nodes as external implementation details, and keep your global CSS narrowly scoped so development tooling cannot affect your application layout.

Leave a Reply

Your email address will not be published. Required fields are marked *