개발/React

[React] 팝업 페이지 만들기 - Modal 없이 깡구현

emfpdlzj 2025. 12. 31. 17:47

새로 준비중인 공모전에서 팝업 페이지를 구현해보기로 했다.

추가적인 페이지 이동이 없고, 간단해보였기 때문이다. (근데 구현은 안 간단한 듯 하다.)

pc버전의 인스타그램 같은 창을 생각하면 이해가 쉬울 것 같다.

 

modal 없이도 배경 어둡게 + 팝업으로 띄운 것 같은 효과를 통해 모달의 느낌을 줄 수 있다.

 


 

종료조건

x버튼을 누르거나,  esc를 누르거나, 팝업창 밖의 백그라운드를 누르면 종료되도록 하였다.

 

1.x버튼 누르기 : 그냥 버튼 컴포넌트를 만들면됨

2.esc누르면 종료: useEffect를 통해 Escape를 누르면 onClose()됨. 그리고 자식 페이지들에서 onclose시 navigate(-1)되도록 하였음.

3.백그라운드 누르면 종료: 가장 아래에 백그라운드 div를 만들어준다. 그리고 이 div를 누르면 onclose가 실행되도록 하였다.

 

그려지는 방식

각 레이어는 fixed + z-index를 이용해 화면 전체에 겹쳐 그려진다.

 

2층: 팝업 페이지

1 층: 백그라운드용 회색 페이지 (여기 누르면 종료)

0 층: 원래 페이지 ( 스크롤 방지 걸어줘야함)

 

이 이후로 팝업 페이지 내에서 추가적인 페이지 이동이 생기면, 3층 부터 추가로 그려진다. 

 

활용 및 실코드 

 

실제론 이런식으로 구현했다. 페이지 내에서 스크롤/페이지 이동도 아주 잘 된다 !

tailwind css를 통해 테두리도 둥글게 해보고,
Modal shell을 정의하여 여러 팝업페이지에 공통 header를 정의해줬다.

// ModalShell.jsx
import ...
export default function ModalShell({ onClose, children }) {
    useEffect(() => { //모달이 실행되면, 원래 페이지의 스크롤을 막음.
        const prev = document.body.style.overflow;
        document.body.style.overflow = "hidden";
        return () => {
            document.body.style.overflow = prev;
        };
    }, []);

    useEffect(() => { //키 누르면 종료 
        const onKey = (e) => {
            if (e.key === "Escape") onClose();
        };
        window.addEventListener("keydown", onKey);
        return () => window.removeEventListener("keydown", onKey); //keydown이벤트 리스너를 윈도우에 붙임.
    }, [onClose]);

    return (
        //바깥 클릭시 닫힘
        <div className="fixed inset-0 z-[9999]" onClick={onClose}>
            {/* 시각용 오버레이 */}
            <div className="absolute inset-0 bg-black/40" />
            {/* 모달 래퍼*/}
            <div className="absolute inset-0 flex items-center justify-center p-8">
                {/* 모달 본체 클릭은 닫기 막음. */}
                <div
                    className={[
                        "relative overflow-hidden rounded-[20px] bg-white shadow-xl",
                        "w-[1240px] h-[720px] max-w-[95vw] max-h-[95vh]",
                    ].join(" ")}
                    onClick={(e) => e.stopPropagation()}
                >
                    <div className="flex items-center justify-between px-8 border-b mt-6 border-white">
                        ... //공통헤더 
                    </div>

                    <div className="h-[calc(720px-56px)] overflow-y-auto">
                        {children}  //모달페이지 내용 
                    </div> 
                </div>
            </div>
        </div>
    );
}

 

이후 다른 자식 팝업페이지에서 아래와같은 방식으로 ModalShell을 활용하면 된다.

import ModalShell from "./ModalShell.jsx";
...

export default function ChildrenModalPage() {
...

return (
    <ModalShell onClose={close}>
    	...
    </ModalShell>
    );
 }

 

 


배운점

이번 구현을 통해 단순히 “모달을 띄운다”는 기능도   이벤트 처리, 스크롤 제어, 레이어 구조 등   여러 요소를 함께 고려해야 한다는 걸 체감했다.

 

다음 단계로는

- 모달 스택 관리, 여러 모달이 겹칠 때 스크롤 처리, 접근성

 

등을 개선해볼 계획이다. 무조건 라이브러리 쓰는거보다 깡구현도 재밌는 점이 있는 듯 하다.