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.
Rendu des enfants en dehors de la hiérarchie DOM parente tout en conservant la propagation des événements React.
ReactDOM.createPortal(children, domNode) rend un sous-arbre React dans un nœud DOM différent de celui où le parent se rend. Bien que le composant apparaisse à un endroit différent dans le DOM (comme une modale au niveau du body), il reste un enfant dans l'arbre de composants React. Cela signifie que le contexte, les événements et le cycle de vie React fonctionnent exactement comme si le portail était intégré.
createPortal(children, document.getElementById('modal-root')) dit à React de rendre les enfants dans #modal-root au lieu du sous-arbre DOM du parent. La sortie DOM est complètement séparée du DOM du parent.
Malgré le rendu ailleurs dans le DOM, le composant portal est conceptuellement un enfant du composant qui le rend. Il obtient les mêmes valeurs de contexte, les mêmes props React et participe au même arbre Fiber.
Si vous cliquez dans un portail, l'événement click se propage dans l'arbre de composants React jusqu'au parent — même si dans le DOM, le nœud du portail est en dehors du sous-arbre DOM du parent. Le système d'événements synthétiques de React opère sur l'arbre Fiber, pas sur l'arbre DOM.
Un composant portal peut lire les valeurs de contexte d'un Provider qui est un ancêtre dans l'arbre de composants React, même si le portail se rend dans un nœud DOM complètement différent.
ReactDOM.createPortal(children, domNode). Rend les enfants React dans domNode au lieu du conteneur DOM parent.
Deux hiérarchies différentes. L'arbre React gouverne le contexte, les événements et les props. L'arbre DOM gouverne la mise en page visuelle et l'héritage CSS.
Les événements de portail se propagent dans l'arbre de composants React (pas dans l'arbre DOM), donc les composants parents reçoivent les événements des enfants portail.
Cas d'utilisation portail le plus courant : rendre les modales et infobulles à document.body pour éviter le découpage par overflow:hidden ou z-index des éléments ancêtres.
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}
Les portails résolvent un problème CSS fondamental : les modales, infobulles et menus déroulants doivent visuellement 'échapper' à leurs conteneurs parents. Le CSS ancestral comme overflow:hidden, les contextes d'empilement z-index et les propriétés transform peuvent découper ou repositionner les enfants positionnés absolument. En se rendant à document.body, les portails contournent toutes ces contraintes tout en préservant le modèle de composants 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).