이벤트 버블링은 DOM에서 이벤트가 발생했을 때, 그 이벤트가 상위 요소로 전파되는 현상입니다. 모달 컴포넌트에서는 이 특성을 이해하고 적절히 처리하는 것이 중요합니다.
자식 요소에서 발생한 이벤트가 부모 요소로 '거품(bubble)'처럼 올라가는 현상입니다. 예를 들어, 버튼을 클릭하면 버튼 → 버튼의 부모 → 그 부모의 부모... 순으로 클릭 이벤트가 전파됩니다.
모달 구현 시 흔히 발생하는 패턴:
<div className="overlay" onClick={closeModal}>
<div className="modal-content">
{/* 모달 내용 */}
</div>
</div>
여기서 배경(overlay)을 클릭하면 모달이 닫히도록 설계했습니다. 하지만 모달 내용을 클릭해도 그 이벤트가 배경까지 버블링되어 모달이 의도치 않게 닫히게 됩니다.
이벤트 버블링을 막기 위해 stopPropagation() 메서드를 사용합니다:
<div className="overlay" onClick={closeModal}>
<div className="modal-content" onClick={(e) => e.stopPropagation()}>
{/* 모달 내용 */}
</div>
</div>
e.stopPropagation()은 이벤트가 더 이상 상위 요소로 전파되지 않도록 중단시킵니다. 이렇게 하면 모달 내용을 클릭했을 때는 이벤트가 배경까지 전달되지 않아 모달이 닫히지 않습니다.
const Modal = ({ isOpen, onClose, children }) => {
if (!isOpen) return null;
return createPortal(
<div
className="fixed inset-0 bg-black/50 flex items-center justify-center"
onClick={onClose}
>
<div
className="bg-white rounded-lg p-6 max-w-lg w-full"
onClick={(e) => e.stopPropagation()}
>
{children}
</div>
</div>,
document.body
);
};
이렇게 구현하면 사용자가 모달 외부(배경)를 클릭할 때만 모달이 닫히고, 모달 내부를 클릭할 때는 모달이 계속 열려 있게 됩니다.