[React] 부모의 CSS에서 탈출할 수 있는 createPortal

윤하빈·2026년 3월 26일

개발 공부

목록 보기
3/13
post-thumbnail

리액트로 모달(Modal)이나 툴팁(Tooltip)을 만들다 보면, 분명 z-index를 9999로 줬는데도 배경 뒤로 숨거나 부모 박스 안에서 잘려 보이는 현상을 겪을 수 있다

이때 필요한 것이 바로 createPortal이다!


1. createPortal이란?

보통 리액트 컴포넌트는 부모 컴포넌트의 DOM 구조 안에 렌더링된다. 하지만 createPortal을 사용하면 컴포넌트의 논리적 위치(코드 위치)는 유지하면서, 물리적 위치(실제 그려지는 곳)만 다른 DOM 노드로 옮길 수 있다.

2. 왜 사용해야 할까?

  • CSS 제약 탈출: 부모 요소에 z-index, overflow: hidden, transform 설정이 있으면 자식인 모달은 그 영향을 받는다. 포탈을 쓰면 <body> 직계 자식으로 보낼 수 있어 이런 제약에서 자유롭다.
  • 이벤트 버블링 유지: 물리적 위치는 옮겨지지만, 리액트 안에서의 이벤트(클릭 등)는 원래 코드 위치의 부모로 그대로 전달된다.

3. 실전 사용법 (3단계)

1단계: 목적지 만들기 (index.html)

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

2단계: 포탈 컴포넌트 작성

react-dom에서 제공하는 createPortal을 사용

import { createPortal } from 'react-dom;

function Modal({ children }) {
  const mountNode = document.getElementById('modal-root');
  
  if (!mountNode) return null;

  return createPortal(
    <div className="modal-overlay">
      <div className="modal-content">{children}</div>
    </div>,
    mountNode // 👈 어디로 보낼지 결정
  );
}

3단계: 호출하기

코드 위치는 상관없이 부모 컴포넌트 어디서든 호출

function CommunityPage() {
  const [isOpen, setIsOpen] = useState(false);

  return (
    <div>
      <h1>자유게시판</h1>
      <button onClick={() => setIsOpen(true)}>글쓰기</button>
      
      {/* 화면상으로는 modal-root에 그려지지만, 로직은 여기서 관리! */}
      {isOpen && <Modal>게시글 작성 폼입니다.</Modal>}
    </div>
  );
}

💡결론

DOM을 독립시켜 주는 것이 포탈의 핵심!


1개의 댓글

comment-user-thumbnail
2026년 3월 26일

DOM 독립이라니~~ 대한독립만세입니다~~ 🇰🇷

답글 달기