El problema del recorte
Imagina un modal definido dentro de una tarjeta con overflow: hidden y
position: relative. Aunque en React el modal sea "hijo" de la tarjeta, en el
DOM quedaría recortado por esos estilos y atrapado en su contexto de
apilamiento (z-index). Es el típico caso de un dropdown que se corta o un
modal que aparece detrás de otro elemento.
React.createPortal
Un Portal te permite renderizar unos hijos en otro nodo del DOM, fuera de la jerarquía visual del componente padre, sin dejar de pertenecer al árbol de React:
import { createPortal } from "react-dom";
function Modal({ children }) {
return createPortal(
<div className="modal-overlay">{children}</div>,
document.body // se monta directamente en <body>
);
}
createPortal(children, domNode) recibe qué renderizar y dónde (un nodo
del DOM ya existente, típicamente document.body o un <div id="modal-root">).
La clave: se mueve el DOM, no el árbol de React
Aunque el modal aparezca en <body>, sigue siendo hijo de Modal en el árbol
de React. Esto tiene dos consecuencias importantes:
- El contexto se mantiene: el componente portado lee los mismos
Context, props y estado que si estuviera "en su sitio". No pierde su conexión con la app. - Los eventos burbujean por el árbol de React, no por el DOM. Un
onClickdentro del portal burbujeará hasta los padres React delModal, aunque en el DOM esté en otra rama.
Casos de uso típicos
- Modales y diálogos: se montan en
<body>para cubrir toda la pantalla. - Tooltips y menús flotantes: evitan que
overflowoz-indexlos recorten. - Notificaciones (toasts): viven en una capa propia encima de todo.
Nota del entorno: la validación de
createPortalno es fiable en el runtime de pruebas, por lo que en este módulo lo trabajamos de forma conceptual.