Join the discussion
Comments
Loading comments...
Cookie preferences
We use essential cookies for sign-in and preferences. With your permission, we also use basic analytics to improve lessons.
Join the discussion
Loading comments...
We use essential cookies for sign-in and preferences. With your permission, we also use basic analytics to improve lessons.
Reactのイベントバブリングを維持しながら親DOM階層外に子をレンダリング。
ReactDOM.createPortal(children, domNode)は、親がレンダリングするDOMノードとは異なるDOMノードにReactのサブツリーをレンダリングします。コンポーネントはDOM上では別の場所(モーダルがbodyレベルにあるなど)に表示されますが、Reactコンポーネントツリーでは依然として子として扱われます。つまり、context、イベント、Reactライフサイクルはポータルがインラインであるかのように正確に機能します。
createPortal(children, document.getElementById('modal-root'))は、childrenを親のDOMサブツリーではなく#modal-rootにレンダリングするようReactに指示します。DOMの出力は親のDOMとは完全に切り離されています。
DOMの別の場所にレンダリングされていても、ポータルコンポーネントはそれをレンダリングするコンポーネントの概念上の子です。同じcontext値、同じReact propsを受け取り、同じFiberツリーに参加します。
ポータル内をクリックすると、クリックイベントはReactのコンポーネントツリーを通じて親にバブルします — DOMではポータルのノードが親のDOMサブツリーの外側にあっても同様です。Reactの合成イベントシステムはDOMツリーではなくFiberツリー上で動作します。
ポータルコンポーネントは、ポータルが完全に異なるDOMノードにレンダリングされていても、ReactのコンポーネントツリーでProviderの祖先にあたるものからcontext値を読み取ることができます。
ReactDOM.createPortal(children, domNode)。React childrenを親のDOMコンテナではなくdomNodeにレンダリングします。
2つの異なる階層。Reactツリーはcontext、イベント、propsを管理します。DOMツリーは視覚的なレイアウトとCSSの継承を管理します。
ポータルのイベントはReactコンポーネントツリー(DOMツリーではなく)を通じてバブルするため、親コンポーネントはポータルの子からのイベントを受け取ります。
最も一般的なポータルのユースケース:祖先要素のoverflow:hiddenやz-indexのクリッピングを避けるため、モーダルやツールチップをdocument.bodyにレンダリングします。
1import { createPortal } from 'react-dom';23function Modal({ isOpen, onClose, children }) {4 if (!isOpen) return null;56 // Renders into document.body, not into parent's DOM node7 return createPortal(8 <div className="modal-overlay" onClick={onClose}>9 <div className="modal-content" onClick={e => e.stopPropagation()}>10 {children}11 </div>12 </div>,13 document.body // the target DOM node14 );15}1617// Usage — modal is a React child of Card,18// but renders at document.body in the DOM19function Card() {20 const [open, setOpen] = useState(false);21 return (22 <div style={{ overflow: 'hidden' }}> {/* won't clip modal */}23 <button onClick={() => setOpen(true)}>Open Modal</button>24 <Modal isOpen={open} onClose={() => setOpen(false)}>25 Content here!26 </Modal>27 </div>28 );29}
ポータルはCSSの根本的な問題を解決します:モーダル、ツールチップ、ドロップダウンは親コンテナから視覚的に「抜け出す」必要があります。overflow:hidden、z-indexのスタッキングコンテキスト、transformプロパティなどの祖先CSSは、絶対位置指定された子をクリップしたり再配置したりすることがあります。document.bodyにレンダリングすることで、ポータルはこれらの制約をすべて回避しながらReactのコンポーネントモデルを維持します。
Your card component has `overflow: hidden` to clip long text. When you add a dropdown menu or modal inside the card, it gets clipped by the card's overflow — users can't see the full dropdown.
The modal/dropdown is a DOM child of the card, so CSS `overflow: hidden` on the card clips everything inside it. You could remove overflow:hidden but that breaks the text truncation. CSS `z-index` alone can't escape an overflow context.
Use a portal to render the modal at `document.body`. It escapes the card's CSS stacking context entirely. React events still bubble through the React tree (card → modal), so onClick handlers and context providers work normally — only the DOM position changes.
Takeaway: Portals decouple the DOM hierarchy from the React component hierarchy. This is essential for any UI that needs to visually 'break out' of its container: modals, tooltips, dropdowns, toast notifications, and floating menus.
You're building a micro-frontend where your React widget needs to render inside a specific container managed by a host application (not your root div). The host gives you a `#widget-container` div.
Your React app renders into `#app-root` by default. You can't simply move your component tree because it needs to share context and state with other parts of your React app.
Use portals to render specific components into `#widget-container` while keeping them in the same React tree. They still receive context from their React parent, participate in event bubbling, and share state — they just render into a different DOM node.
Takeaway: Portals are the foundation for micro-frontend integration patterns. They let you mount React components into external DOM nodes while preserving the full React component model (context, error boundaries, event delegation).