Tutorials Logic, IN info@tutorialslogic.com

React Portals Modals Tooltips Outside DOM

What are Portals in React?

Portals let you render part of a React component into a different place in the DOM. Normally, a component renders inside its parent element. A portal allows that same component to stay in the React tree while its HTML is inserted somewhere else, such as directly inside document.body or a separate DOM node like #modal-root.

This is useful when a UI element needs to visually escape its container. For example, a modal should appear above the whole screen, a tooltip should float over other elements, and a dropdown should not be cut off by a parent with overflow: hidden.

Even though the portal content is rendered elsewhere in the DOM, React still treats it as part of the same component tree. That means props, state, context, and event bubbling still work the React way.

Why Portals Are Needed

  • Modals often need to appear above the entire page
  • Tooltips and dropdowns should not be clipped by parent containers
  • Floating UI elements often need a different stacking context
  • Portals help solve z-index and overflow layout problems cleanly
  • They allow better separation between React structure and DOM placement

How createPortal Works

React provides portals through createPortal from react-dom. It takes two main values:

The component is still written and managed in the same React app, but its output is mounted into a different DOM node.

  • The JSX you want to render
  • The DOM node where that JSX should appear

Basic Portal Syntax

Basic Portal Syntax
import { createPortal } from 'react-dom'



function Example() {

    return createPortal(

        <div>This content is rendered somewhere else in the DOM.</div>,

        document.getElementById('portal-root')

    )

}

Portal Mount Points

React portals are easiest to manage when the DOM has a second mount point beside the main root. Keeping modal or tooltip content in a separate container avoids z-index fights and lets the rendered tree stay where React expects it while the element appears elsewhere in the DOM.

index.html Setup

index.html Setup
<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8" />

    <meta name="viewport" content="width=device-width, initial-scale=1.0" />

    <title>React App</title>

</head>

<body>

    <div id="root"></div>

    <div id="modal-root"></div>

</body>

</html>

Modal Example with a Portal

A modal is the most common portal example. If you render a modal inside a deeply nested component, it may be affected by the parent layout. Rendering it through a portal avoids those problems and lets the modal sit above the whole page.

Modal with createPortal

Modal with createPortal
import { createPortal } from 'react-dom'

import { useEffect } from 'react'



function Modal({ isOpen, onClose, title, children }) {

    useEffect(() => {

        if (!isOpen) return



        const handleKeyDown = (event) => {

            if (event.key === 'Escape') {

                onClose()

            }

        }



        document.addEventListener('keydown', handleKeyDown)

        document.body.style.overflow = 'hidden'



        return () => {

            document.removeEventListener('keydown', handleKeyDown)

            document.body.style.overflow = ''

        }

    }, [isOpen, onClose])



    if (!isOpen) return null



    return createPortal(

        <div className="modal-overlay" onClick={onClose}>

            <div className="modal-box" onClick={(e) => e.stopPropagation()}>

                <div className="modal-header">

                    <h2>{title}</h2>

                    <button onClick={onClose}>Close</button>

                </div>

                <div className="modal-body">{children}</div>

            </div>

        </div>,

        document.getElementById('modal-root')

    )

}



export default Modal

Modal Example with a Portal - JSX Example

Modal Example with a Portal - JSX Example
import { useState } from 'react'

import Modal from './Modal'



function App() {

    const [open, setOpen] = useState(false)



    return (

        <div style={{ overflow: 'hidden', height: '220px' }}>

            <h2>Portal Example</h2>

            <p>This container has limited space, but the modal will still appear correctly.</p>

            <button onClick={() => setOpen(true)}>Open Modal</button>



            <Modal isOpen={open} onClose={() => setOpen(false)} title="Delete Item">

                <p>Are you sure you want to delete this item?</p>

                <button onClick={() => setOpen(false)}>Cancel</button>

                <button onClick={() => setOpen(false)}>Delete</button>

            </Modal>

        </div>

    )

}

Tooltip Example

Tooltips are another great use case for portals. A tooltip often needs to appear above nearby content and ignore clipping from parent elements. With a portal, the tooltip can be positioned visually where it belongs without being trapped by the local layout.

Tooltip with a Portal

Tooltip with a Portal
import { createPortal } from 'react-dom'

import { useRef, useState } from 'react'



function Tooltip({ text, children }) {

    const [visible, setVisible] = useState(false)

    const [position, setPosition] = useState({ top: 0, left: 0 })

    const triggerRef = useRef(null)



    const showTooltip = () => {

        const rect = triggerRef.current.getBoundingClientRect()



        setPosition({

            top: rect.top + window.scrollY - 36,

            left: rect.left + window.scrollX + rect.width / 2

        })

        setVisible(true)

    }



    return (

        <>

            <span

                ref={triggerRef}

                onMouseEnter={showTooltip}

                onMouseLeave={() => setVisible(false)}

            >

                {children}

            </span>



            {visible && createPortal(

                <div

                    style={{

                        position: 'absolute',

                        top: position.top,

                        left: position.left,

                        transform: 'translateX(-50%)',

                        background: '#222',

                        color: '#fff',

                        padding: '6px 10px',

                        borderRadius: '4px',

                        fontSize: '12px',

                        whiteSpace: 'nowrap',

                        zIndex: 9999

                    }}

                >

                    {text}

                </div>,

                document.body

            )}

        </>

    )

}

Important Portal Behavior

One thing that surprises beginners is that a portal changes where content appears in the DOM, but it does not remove it from the React tree. That leads to several important behaviors:

For example, if a button inside a portal is clicked, React event handling can still reach a parent component higher in the React tree even though the DOM nodes are separated.

  • Context still works inside portal content
  • State still belongs to the original component
  • Events bubble through the React tree, not the visual DOM structure
  • Parent components can still control portal children normally with props

Common Use Cases

  • Modal dialogs
  • Tooltips
  • Dropdown menus
  • Hover cards
  • Toast notifications
  • Full-screen overlays
  • Context menus

Best Practices for Portals

  • Use portals only when layout escape is actually needed
  • Keep portal mount points clearly named such as modal-root
  • Clean up event listeners when the portal closes
  • Handle keyboard interactions like the Escape key for modals
  • Prevent background scrolling when full-screen overlays are open
  • Think about accessibility, especially focus management and screen reader support

Portals Failure Cases

  • Forgetting to create the target DOM node in index.html
  • Assuming the portal is outside the React tree
  • Not removing event listeners when the portal unmounts
  • Ignoring keyboard and focus behavior in modals
  • Using portals for normal layout when plain component structure would be simpler

Summary

React portals solve a visual placement problem. They let you keep a component in the same React hierarchy while rendering its HTML somewhere else in the DOM. This is especially useful for UI elements that must appear above the rest of the page or escape container layout restrictions.

Once you understand createPortal, you can build modals, tooltips, overlays, and other floating UI in a cleaner and more reliable way.

Before you move on

React Portals Modals Tooltips Outside DOM Mastery Check

5 checks
  • Portals let you render part of a React component into a different place in the DOM.
  • Normally, a component renders inside its parent element.
  • This is useful when a UI element needs to visually escape its container.
  • For example, a modal should appear above the whole screen, a tooltip should float over other elements, and a dropdown should not be cut off by a parent with overflow: hidden.
  • Even though the portal content is rendered elsewhere in the DOM, React still treats it as part of the same component tree.

Portal Boundary

  • Visual escape is not event isolation

    A portal changes DOM placement but remains in the React tree, so context and event bubbling still follow React ancestry. Handle modal events and focus explicitly.

React JS Questions Learners Ask

A portal changes where the DOM nodes are mounted, but it does not remove the modal from the React component tree. Events still bubble through the React tree to the parent that rendered the portal.

Opening a modal should move focus into the dialog, usually to the first useful control or the dialog container. Closing it should return focus to the element that opened it.

createPortal needs a real DOM node, such as the modal-root shown in the index.html setup. In development you may have added it locally, while a different HTML template, micro-frontend shell, or SSR document in production omits it. document.getElementById then returns null and the portal cannot mount.

Browse Free Tutorials

Explore 500+ free tutorials across 20+ languages and frameworks.