🪟 React에서 모달(Dialog) 시스템 제대로 설계하기|Context로 상태 관리부터 포탈 구현까지
안녕하세요, 퍼블리셔 노미입니다!
웹에서 흔히 볼 수 있는 UI 중 하나인 모달 창(Modal Dialog)은 사용자에게 알림을 주거나, 확인을 받거나, 추가 정보를 보여주는 데 자주 사용됩니다.
React에서 모달을 구현할 땐 단순히 `display: block
`으로 보여주는 것을 넘어서 Context로 전역 관리하거나, React Portal로 구조를 분리하거나, 다중 모달 & 접근성까지 고려해야 할 부분이 많아요.
오늘은 그런 모달 시스템을 기초부터 실전 패턴까지 정리해드릴게요.
📌 모달이란?
모달(Modal)은 현재 UI 흐름을 중단하고, 사용자에게 특정 작업을 유도하는 오버레이 창입니다.
주로 배경을 어둡게 하고, 가운데에 작은 박스를 띄우는 형태로 사용되죠.
- 경고창 / 확인창
- 로그인 / 회원가입 팝업
- 이미지 확대 보기
🔧 기본 모달 컴포넌트 구조
// Modal.js
export default function Modal({ isOpen, onClose, children }) {
if (!isOpen) return null;
return (
<div className="overlay">
<div className="modal">
<button onClick={onClose}>닫기</button>
{children}
</div>
</div>
);
}
스타일 예시 (CSS)
.overlay {
position: fixed;
top: 0; left: 0;
width: 100vw; height: 100vh;
background: rgba(0, 0, 0, 0.4);
display: flex;
align-items: center;
justify-content: center;
}
.modal {
background: white;
padding: 2rem;
border-radius: 8px;
max-width: 500px;
width: 100%;
}
📡 props로 제어하는 기본 사용 예시
function App() {
const [isOpen, setIsOpen] = useState(false);
return (
<>
<button onClick={() => setIsOpen(true)}>모달 열기</button>
<Modal isOpen={isOpen} onClose={() => setIsOpen(false)}>
<p>모달 내용입니다</p>
</Modal>
</>
);
}
→ 기본적인 구현은 위처럼 state를 사용해서 show/hide 처리할 수 있어요.
🌍 Context로 전역 모달 시스템 만들기
1. 컨텍스트 생성
const ModalContext = createContext();
export function ModalProvider({ children }) {
const [modal, setModal] = useState(null);
const openModal = (content) => setModal(content);
const closeModal = () => setModal(null);
return (
<ModalContext.Provider value={{ openModal, closeModal }}>
{children}
{modal && (
<div className="overlay">
<div className="modal">
<button onClick={closeModal}>닫기</button>
{modal}
</div>
</div>
)}
</ModalContext.Provider>
);
}
export function useModal() {
return useContext(ModalContext);
}
2. 어디서든 호출하기
function AnyComponent() {
const { openModal } = useModal();
return (
<button onClick={() => openModal(<p>모달 내용입니다</p>)}>
모달 열기
</button>
);
}
→ Context를 활용하면 어느 컴포넌트에서도 모달을 열고 닫을 수 있어요.
🧭 React Portal로 구조 분리
모달은 종종 DOM 트리 상 다른 곳에 위치해야 올바르게 렌더링됩니다. 이때 사용하는 것이 React Portal입니다.
index.html에 모달 전용 DOM 추가
<body>
<div id="root"></div>
<div id="modal-root"></div>
</body>
Modal.js 수정
import ReactDOM from "react-dom";
export default function Modal({ isOpen, onClose, children }) {
if (!isOpen) return null;
return ReactDOM.createPortal(
<div className="overlay">
<div className="modal">
<button onClick={onClose}>닫기</button>
{children}
</div>
</div>,
document.getElementById("modal-root")
);
}
→ 포탈을 통해 DOM 구조를 깨끗하게 분리 가능
🧠 모달에서 자주 발생하는 UX 이슈
- ESC 키로 닫기
- 배경 클릭 시 닫기
- 모달 열리면 스크롤 고정
- 모달 내부 탭 포커스 이동 제한
ESC로 닫기
useEffect(() => {
const handleEsc = (e) => {
if (e.key === "Escape") onClose();
};
window.addEventListener("keydown", handleEsc);
return () => window.removeEventListener("keydown", handleEsc);
}, []);
📚 마무리하며
모달은 단순히 열고 닫는 UI 요소가 아닙니다.
기획 단계부터 어디서나 열 수 있어야 하고, 구조 분리가 되어야 하며, 접근성과 UX까지 고려해야 제대로 된 모달 시스템이라고 할 수 있어요.
오늘 배운 방식들을 토대로 여러분만의 모달 매니저 시스템을 만들어보세요!
다음 글에서는 다중 모달, 중첩 모달 설계 또는 애니메이션 모달 컴포넌트화를 다뤄볼게요.
#React모달 #모달설계 #Context전역관리 #ReactPortal #모달UX #모달컴포넌트 #퍼블리셔노미 #리액트UI설계 #프론트엔드실전
'차근차근' 카테고리의 다른 글
JavaScript 비동기 처리 완전 정복|콜백, 프로미스, async/await 흐름 한 번에 이해하기 (1) | 2025.05.05 |
---|---|
React Router로 웹페이지 이동 흐름 완전 정복|SPA 라우팅 구현 모든 방법 (1) | 2025.05.04 |
프론트엔드 상태 관리의 모든 것|Context, Props, 전역 상태 완벽 가이드 (0) | 2025.04.27 |
JSON Server로 나만의 가짜 API 만들기|프론트엔드 개발자를 위한 실전 백엔드 환경 구축 가이드 (0) | 2025.04.26 |
회원가입 & 로그인 기능 구현 흐름 완전 정복|프론트엔드 개발자를 위한 인증 시스템 기초 (0) | 2025.04.25 |