Render Outside the Box: Floating UIs with React.createPortal

Modern UIs often need elements that float above the rest of the page, such as modals, tooltips, popovers, or notifications. But when you try to build these inside your component hierarchy, you quickly hit frustrating limits like overflow clipping, stacking issues, and unpredictable z-index behavior.

In this blog, I will show you how to use React.createPortal to solve these problems by rendering elements outside the normal DOM tree while keeping them fully connected to your React app.

What is React.createPortal?

React.createPortal (syntax React.createPortal(children, container)) is a feature that lets you to render React elements into a DOM node that exists outside the parent’s DOM tree. It allows you to keep your UI where it belongs: in the React tree logically, but in the DOM exactly where it needs to be. The children are still part of the React component hierarchy (they receive context, props, and updates), but in the actual DOM they’re mounted somewhere else.

Basic example:

import React from "react"; 
import ReactDOM from "react-dom";  

function Modal({ children }) {
   return ReactDOM.createPortal(     
	   <div className="modal">{children}</div>,
	   document.body   
   ); 
}

Here, even if <Modal> is rendered deep in your component tree, its DOM nodes appear just before closing </body> tag. React takes on all the job to add the element to DOM and remove it from proper place of DOM after element is unmounted. This solves problems with stacking, clipping, and positioning that CSS alone cannot handle reliably. Essentially we render our element above all mounted React application and can apply any placement we want. Also it possible to define a particular places to render target element.

Setting Up Named Portals

A good practice is to define multiple “portal roots” in your index.html to organize different kinds of overlays. You can use them as a destination to render every particular sort of floating UI elements. Technically it just unique-named DOM elements in .html file along with root DOM element where the main app is being mounted.

Example index.html

<body>   
	<div id="root"></div>    
	<!-- Named portal targets -->   
	<div id="modal-root"></div>   
	<div id="tooltip-root"></div>   
	<div id="notification-root"></div> 
</body>

Example Components

import React from "react"; 
import ReactDOM from "react-dom";
  
export function Modal({ children }) {   
	return ReactDOM.createPortal(     
		<div className="modal">{children}</div>,     
		document.getElementById("modal-root")   
	); 
}  

export function Tooltip({ children }) {   
	return ReactDOM.createPortal(     
		<div className="tooltip">{children}</div>,
		document.getElementById("tooltip-root")
	);
}

export function Notification({ message }) {   
	return ReactDOM.createPortal(     
		<div className="notification">{message}</div>,
		document.getElementById("notification-root")   
	);
}

This way, your DOM stays clean and responsibilities clear: modals in #modal-root, tooltips in #tooltip-root, and so on. It is not a strictly required practice, rather a useful and convenient way to organize the markup.

UI Cases for Custom Mounting Via React.createPortal

The obvious solution for such rendering is just to add absolutely position the element with a high z-index without any magic with native React feature. The issue is that CSS alone can’t overcome parent boundaries.

The main and most painful one is Overflow Clipping. If a parent has overflow: hidden or overflow: auto, absolutely positioned children will still be cut off. Portals avoid this by moving the element outside of the clipping container.

With pure CSS it can look like

Clipped css example

When we place floating element to the root DOM element we can apply its placement relatively to the whole document (it needs some calculations, of course). For several particular cases it provides a silver bullet to resolve clipping issue when avoiding overflow parent boundaries is impossible.

The other benefits are:

  • Z-Index Limitations – Z-index only works within stacking contexts. If a parent has its own stacking context, it might prevent your modal or tooltip from rising above other UI elements.
  • Isolation – with absolute positioning, your component is still “tied” to its parent’s DOM. Styles can cascade down unexpectedly. Portals isolate overlays in dedicated containers.
  • Predictability – a tooltip placed in a deeply nested component tree may require awkward position calculations. With portals, you can anchor it to the document and calculate positions relative to target elements more easily.

So general conclusion is simple – we can use position: absolute for local UI tweaks and portals – when the element must escape the layout or stacking context entirely.

Adding Positioning: Example with a Modal

Imagine we want to have a modal to appear next to a button or a tile, but the layout has scrollable containers with overflow: hidden.

Here’s how you can handle positioning:

import React, { useEffect, useState } from "react"; 
import ReactDOM from "react-dom"; 

export function Modal({ targetRef, children }) {
   const [pos, setPos] = useState({ top: 0, left: 0 });   
   
   useLayoutEffect(() => {     
	if (targetRef.current) {       
		const rect = targetRef.current.getBoundingClientRect();       
		setPos({         
		   top: rect.bottom + window.scrollY + 8,         
		   left: rect.left + window.scrollX,       
		});     
	}   
   }, [targetRef]);    
	
   return ReactDOM.createPortal(     
	<div       
		className="modal"       
		style={{         
			position: "absolute",         
			top: pos.top,         
			left: pos.left,       
			}}>				
			{children}
	</div>,    
	document.body
   );
}

Usage:

function App() {
   const buttonRef = React.useRef(null);  
   return (     
	   <div>       
		   <button ref={buttonRef}>Hover me</button> 
		   <Modal targetRef={buttonRef}>Modal content</Tooltip>
	   </div>
  ); 
}

Here:

  • The tooltip is positioned relative to the button using getBoundingClientRect().
  • Even if the button is inside a scrollable container, the tooltip renders in document body, avoiding clipping.

!NB:

  • use native React hook useLayoutEffect – it will do calculations when position of element is known but before element be displayed on the screen. After calculations it will set the state, which cause re-render of the component but with the right positioning. It prevents blinking and other not desirable visual pitfalls
  • if you have to use some params from previous state, don’t do like this:
// Don't

useLayoutEffect(() => {
	const positions = {
		...
	};
	setSomeState((prevState) => {
		return {
			...prevState,
			...positions
		};
	});
}, []);

That will break rendering cycle and not desirable visual pitfalls will occur

// Do this instead

useLayoutEffect(() => {
	const positions = {
		// variable, that represents previous state
		...someState,
		// any additional params
	};
	setSomeState(positions);
}, []);

Common Pitfalls

  • Event Bubbling Confusion – React events bubble through the component tree, not the DOM tree. This may confuse debugging
  • Accessibility Gaps – portals don’t provide focus traps, keyboard navigation, or ARIA roles. For common cases modals, use regular UI libraries, or take care about them by your own
  • Multiple Roots Chaos – if you create too many portal roots without documentation, maintainability suffers
  • Server-Side Rendering (SSR) – if portal containers (#modal-root, etc.) don’t exist on the client, you’ll hit hydration mismatches. Always ensure they’re present in index.html

Conclusions

React.createPortal solves real-world problems that CSS can’t fix and manage alone: clipping, stacking context conflicts, and layout unpredictability. Using portals has several pros and cons:

Best Use Cases for Portals:

  • Custom modals and dialogs which must appear above all other UI
  • Prevention of clipping and allow flexible positioning of tooltips and popovers
  • Setting of global messages which need their own UI layer
  • Managing of right-click or floating context menus which benefit from isolation.

When to Avoid Portals:

  • If CSS fixes suffice then don’t over-engineer
  • For small, local UI or effects like badges, dropdowns or progress bars inside a card
  • In performance-critical scenarios – too many scattered portals can complicate rendering and debugging.

If you are building complex user interfaces in React and want to avoid layout and clipping issues, Trailhead can help. Our team has deep experience solving real-world UI challenges with React, .NET, and modern cloud platforms. Contact us to learn how we can help you design clean, scalable front-end architectures that work seamlessly with your existing systems.

Picture of Alex Movchan

Alex Movchan

Alex started his professional path in finance and banking and devoted at least 15 years to the financial industry before switching to software engineering. Now he has over 7 years of experience as a full-stack developer of web applications. Alex is experienced in all the popular front-end Javascript frameworks, TypeScript, and plain old Javascript itself. He is also closely familiar with NodeJS as a backend technology. His academic background gives him an advantage in algorithms, statistics, and data analysis. Alex likes a result-oriented approach to software development, which he likes to execute in a reliable and solution-oriented manner. He likes to be up-to-date with the latest trends and best practices and even enjoys learning a little in connected spheres such as mobile development.

Free Consultation

Sign up for a FREE consultation with one of Trailhead's experts.

"*" indicates required fields

This field is for validation purposes and should be left unchanged.

Related Blog Posts

We hope you’ve found this to be helpful and are walking away with some new, useful insights. If you want to learn more, here are a couple of related articles that others also usually find to be interesting:

Our Gear Is Packed and We're Excited to Explore With You

Ready to come with us? 

Together, we can map your company’s software journey and start down the right trails. If you’re set to take the first step, simply fill out our contact form. We’ll be in touch quickly – and you’ll have a partner who is ready to help your company take the next step on its software journey. 

We can’t wait to hear from you! 

Main Contact

This field is for validation purposes and should be left unchanged.

Together, we can map your company’s tech journey and start down the trails. If you’re set to take the first step, simply fill out the form below. We’ll be in touch – and you’ll have a partner who cares about you and your company. 

We can’t wait to hear from you! 

Montage Portal

Montage Furniture Services provides furniture protection plans and claims processing services to a wide selection of furniture retailers and consumers.

Project Background

Montage was looking to build a new web portal for both Retailers and Consumers, which would integrate with Dynamics CRM and other legacy systems. The portal needed to be multi tenant and support branding and configuration for different Retailers. Trailhead architected the new Montage Platform, including the Portal and all of it’s back end integrations, did the UI/UX and then delivered the new system, along with enhancements to DevOps and processes.

Logistics

We’ve logged countless miles exploring the tech world. In doing so, we gained the experience that enables us to deliver your unique software and systems architecture needs. Our team of seasoned tech vets can provide you with:

Custom App and Software Development

We collaborate with you throughout the entire process because your customized tech should fit your needs, not just those of other clients.

Cloud and Mobile Applications

The modern world demands versatile technology, and this is exactly what your mobile and cloud-based apps will give you.

User Experience and Interface (UX/UI) Design

We want your end users to have optimal experiences with tech that is highly intuitive and responsive.

DevOps

This combination of Agile software development and IT operations provides you with high-quality software at reduced cost, time, and risk.

Trailhead stepped into a challenging project – building our new web architecture and redeveloping our portals at the same time the business was migrating from a legacy system to our new CRM solution. They were able to not only significantly improve our web development architecture but our development and deployment processes as well as the functionality and performance of our portals. The feedback from customers has been overwhelmingly positive. Trailhead has proven themselves to be a valuable partner.

– BOB DOERKSEN, Vice President of Technology Services
at Montage Furniture Services

Technologies Used

When you hit the trails, it is essential to bring appropriate gear. The same holds true for your digital technology needs. That’s why Trailhead builds custom solutions on trusted platforms like .NET, Angular, React, and Xamarin.

Expertise

We partner with businesses who need intuitive custom software, responsive mobile applications, and advanced cloud technologies. And our extensive experience in the tech field allows us to help you map out the right path for all your digital technology needs.

  • Project Management
  • Architecture
  • Web App Development
  • Cloud Development
  • DevOps
  • Process Improvements
  • Legacy System Integration
  • UI Design
  • Manual QA
  • Back end/API/Database development

We partner with businesses who need intuitive custom software, responsive mobile applications, and advanced cloud technologies. And our extensive experience in the tech field allows us to help you map out the right path for all your digital technology needs.

Our Gear Is Packed and We're Excited to Explore with You

Ready to come with us? 

Together, we can map your company’s tech journey and start down the trails. If you’re set to take the first step, simply fill out the contact form. We’ll be in touch – and you’ll have a partner who cares about you and your company. 

We can’t wait to hear from you! 

Thank you for reaching out.

You’ll be getting an email from our team shortly. If you need immediate assistance, please call (616) 371-1037.