Mahamudul Hasan Rubel
HomeBlogCoursesAboutProjectsSkillsExperiencePhotosContact
Mahamudul Hasan Rubel

Senior Software Engineer crafting high-performance web applications and SaaS platforms.

Navigation

  • Home
  • Blog
  • Courses
  • About
  • Projects
  • Skills
  • Experience
  • Photos
  • Contact

Get in Touch

Available for senior/lead roles and consulting.

bd.mhrubel@gmail.comHire Me

Subscribe to the newsletter

Get new articles and course lessons delivered to your inbox. No spam, unsubscribe anytime.

© 2026 Mahamudul Hasan Rubel. All rights reserved.

Built with using Next.js 16 & Tailwind v4

Back to Blog
Lesson 38 of the Advanced React: Performance, Architecture & Patterns course
ReactJune 28, 20264 min read

Using Portals for UI Overlays: A Senior Engineer’s Guide

Learn to use React Portals to break out of the DOM hierarchy for modals, tooltips, and overlays while maintaining full state and accessibility control.

ReactPortalsDOMUIAccessibilityModalsjavascriptfrontend

Previously in this course, we explored Managing Global Modals: A Scalable Pattern for React UI, which taught us how to handle modal visibility without prop drilling. While that lesson focused on state architecture, this lesson focuses on the DOM rendering strategy: Portals.

Portals provide a first-class way to render children into a DOM node that exists outside the hierarchy of the parent component. This is critical for UI overlays like modals, dropdowns, and tooltips where CSS properties like overflow: hidden or z-index on a parent container would otherwise clip or obscure your UI.

The Mechanics of React Portals

At its core, a Portal is a way to break the physical DOM structure while keeping the React logical tree intact. When you render a component via createPortal, React keeps the component within the same context and lifecycle as its parent, but the actual DOM elements are moved to a different location in the document body.

This is essential because of how the browser's box model works. If you have a modal defined inside a nested div with position: relative and z-index: 1, that modal is trapped by its parent's stacking context. By using Portals, we can inject that modal directly into document.body, effectively "escaping" the parent's constraints.

Implementing a Portal Component

To use a portal, we need a target DOM node. We typically create an "overlay root" in our index.html or inject it dynamically on mount.

JSX
import { useEffect, useState } from CE9178">'react';
import { createPortal } from CE9178">'react-dom';

const Portal = ({ children }) => {
  const [container] = useState(() => document.createElement(CE9178">'div'));

  useEffect(() => {
    document.body.appendChild(container);
    return () => document.body.removeChild(container);
  }, [container]);

  return createPortal(children, container);
};

This implementation ensures that the container is appended to the body when the component mounts and cleaned up when it unmounts. Because we use useState to initialize the container, the node is stable across re-renders.

Managing Focus Traps

One common pitfall when moving elements outside the DOM hierarchy is that keyboard navigation can break. If a user tabs through your application, they expect the focus to stay within the modal. Since the modal is now at the end of the document.body, the browser's native tab flow might jump back to the browser address bar rather than the next element in the modal.

To solve this, you need a focus trap. While libraries like react-focus-lock are industry standards, understanding the principle is key:

  1. Capture Focus: On mount, move focus to the first interactive element.
  2. Intercept Tab: Add a listener for the Tab key.
  3. Boundary Check: If the user is on the last element and hits Tab, shift focus back to the first element.

Handling Overlay Positioning

For tooltips or popovers, positioning is rarely static. You often need to calculate the coordinates of a trigger element and position the portal accordingly.

Instead of hardcoding CSS, use the getBoundingClientRect() method on the trigger element. You can then pass these coordinates to your Portal component to apply inline styles or use a library like Floating UI (the evolution of Popper.js) to handle edge cases like screen-edge flipping.

Hands-on Exercise

  1. Create a Tooltip component that uses the Portal pattern above.
  2. Add a ref to a button that triggers the tooltip.
  3. On mouse enter, calculate the trigger's getBoundingClientRect and update the tooltip's absolute position relative to the viewport.
  4. Ensure that the tooltip remains visible even if the trigger is inside a container with overflow: hidden.

Common Pitfalls

  • Event Bubbling: Even though a portal is physically moved in the DOM, it still behaves like a child in the React tree. Events will bubble up to the parent component in the React hierarchy, not the DOM hierarchy. See Mastering Event Bubbling and Propagation in React for details on why this matters.
  • Missing Root Nodes: Don't assume document.body is the only place to mount. Sometimes, you need multiple portals (e.g., one for global notifications, one for modals). Create a dedicated PortalProvider to manage these mount points.
  • SSR Hydration: If you are using Server-Side Rendering (SSR), document is not available during the initial render. Ensure your useEffect or useLayoutEffect handles the creation of the portal container only after the component mounts on the client.

Recap

Portals allow us to transcend the DOM hierarchy without losing the benefits of React’s component model. By carefully managing our mount nodes and implementing robust focus trapping, we can build complex, accessible UI overlays that aren't hampered by the constraints of parent CSS. Remember that while Portals solve the physical placement problem, they don't change how React handles state or events, making them a safe and powerful tool for building high-performance UI components.

Up next: We will dive into Implementing Virtualized Lists to handle rendering massive datasets efficiently.

Previous lessonAdvanced Form HandlingNext lesson Implementing Virtualized Lists
Back to Blog

Similar Posts

ReactJune 28, 20264 min read

Accessibility (a11y) in Advanced Components: A Senior Guide

Master Accessibility (a11y) in React by implementing WAI-ARIA patterns, managing focus traps, and ensuring your complex components are truly inclusive.

Read more
ReactJune 26, 20263 min read

Internationalization Basics: Implementing i18n in React Dashboards

Learn to implement i18n in your React dashboard. We cover managing language state and using context to provide localized UI strings to your components.

Part of the course

Advanced React: Performance, Architecture & Patterns

advanced · Lesson 38 of 47

  1. 1

    Deep Dive into the Reconciliation Algorithm

    4 min
  2. 2

    Profiling with React DevTools

    3 min
  3. 3

    Establishing Performance Budgets

    3 min
Read more
ReactJune 26, 20263 min read

Implementing Keyboard Shortcuts for Accessible React Dashboards

Enhance your React dashboard's accessibility and efficiency by implementing global keyboard shortcuts using useEffect, key mapping, and focus management.

Read more
  • 4

    Strategic use of React.memo

    3 min
  • 5

    Mastering useCallback and useMemo

    4 min
  • 6

    State Colocation Strategies

    4 min
  • 7

    Optimizing Context Providers

    4 min
  • 8

    Advanced Context Composition

    4 min
  • 9

    Eliminating Prop Drilling

    4 min
  • 10

    Introduction to Concurrent React

    4 min
  • 11

    Non-blocking UI with useTransition

    4 min
  • 12

    Handling Deferred Data with useDeferredValue

    3 min
  • 13

    Mastering Suspense for Data Fetching

    4 min
  • 14

    Streaming Server-Side Rendering

    3 min
  • 15

    Designing Compound Components

    3 min
  • 16

    The Render Props Pattern

    4 min
  • 17

    Implementing Control Props

    4 min
  • 18

    Headless UI Architectures

    3 min
  • 19

    Modular Directory Structures

    3 min
  • 20

    Refactoring Monolithic Components

    3 min
  • 21

    Optimistic UI Updates

    3 min
  • 22

    Advanced Cache Invalidation

    4 min
  • 23

    Handling Race Conditions

    4 min
  • 24

    Server-Client State Synchronization

    3 min
  • 25

    Route-level Code Splitting

    4 min
  • 26

    Offloading Tasks with Web Workers

    3 min
  • 27

    Advanced Error Boundaries

    3 min
  • 28

    Monitoring Production Performance

    4 min
  • 29

    Final Project Audit & Optimization

    4 min
  • 30

    Advanced Hook Patterns

    3 min
  • 31

    Managing Global State with Zustand/Redux

    4 min
  • 32

    Testing Performance-Critical Components

    4 min
  • 33

    Static Site Generation (SSG) Patterns

    4 min
  • 34

    Internationalization (i18n) Architecture

    3 min
  • 35

    Accessibility (a11y) in Advanced Components

    4 min
  • 36

    Managing Third-Party Integrations

    3 min
  • 37

    Advanced Form Handling

    4 min
  • 38

    Using Portals for UI Overlays

    4 min
  • 39

    Implementing Virtualized Lists

    4 min
  • 40

    Building Design System Primitives

    3 min
  • 41

    Managing Large-Scale Data Fetching

    Coming soon
  • 42

    Micro-Frontends with React

    Coming soon
  • 43

    Security Best Practices in React

    Coming soon
  • 44

    Advanced Ref Usage

    Coming soon
  • 45

    Memoization Pitfalls

    Coming soon
  • 46

    Mastering React Patterns for Scalability

    Coming soon
  • 47

    Advanced TypeScript with React

    Coming soon
  • View full course