방명록
- [HTML] <dialog> 태그 + createPortal로 모달(modal) 만들기?? [10/3 study]2024년 10월 03일 14시 41분 34초에 업로드 된 글입니다.작성자: 동혁이
<dialog> 태그로 모달(modal) 만들기??
이 글을 작성하게 된 이유
원래는 실제 프로젝트에서 useModal 커스텀훅과 상위 파일인 layout.tsx에 div태그에 id값을 주어야 하는 방법까지 번거롭게 작업했었다.
하지만 강의를 들으면서 상위 layout 파일에 div 요소도 안넣고 더 간편하게 사용하는 방법을 알게 되어 글을 작성해본다.
import '../styles/globals.css'; import Providers from './providers'; export default function RootLayout({ children, }: Readonly<{ children: React.ReactNode; }>) { return ( <html lang="ko"> <body> <Providers>{children}</Providers> <div id="modal-root" /> </body> </html> ); }
'use client'; import { type ReactNode } from 'react'; import ReactDOM from 'react-dom'; import { useModal } from '@/_hooks/useModal'; type ModalProps = { children: ReactNode; isOpen: boolean; onClose: () => void; }; /** * 사용법 * ex) * const { isOpen, openModal, closeModal } = useModal(); * * <button onClick={openModal}>Open Modal</button> <Modal isOpen={isOpen} onClose={closeModal}> <div className="m-auto px-[90px] pb-[28px] pt-[26px] text-right text-[18px] md:w-[540px] md:px-[33px]"> <p className="pb-[43px] pt-[53px] text-center">가입이 완료되었습니다!</p> <span className="flex justify-center md:justify-end"> <button className="h-[42px] w-[138px] rounded-[8px] bg-black text-white">확인</button> // 버튼 컴포넌트 넣어주시면 될 것 같습니다! <button onClick={closeModal}>취소</button> // 버튼 컴포넌트 넣어주시면 될 것 같습니다! </span> </div> </Modal> */ /** * Modal 컴포넌트의 props * * @property {boolean} isOpen - Modal Open 여부 * @property {() => void} onClose - Modal Close 함수 * @property {ReactNode} children - Modal 자식 요소들 */ export default function Modal({ isOpen, onClose, children }: ModalProps) { const { isMounted } = useModal(); const handleBackgroundClick = (event: React.MouseEvent<HTMLDivElement>) => { // 배경 클릭 시 모달 닫기 if (event.target === event.currentTarget) { onClose(); } }; const handleKeyDown = (event: React.KeyboardEvent<HTMLDivElement>) => { if (event.key === 'Escape') { onClose(); } }; if (!isOpen || !isMounted) return null; return ReactDOM.createPortal( <div className="fixed inset-0 z-[9999] flex items-center justify-center bg-black bg-opacity-70" onClick={handleBackgroundClick} onKeyDown={handleKeyDown}> <div className="relative rounded-[12px] bg-white shadow-lg">{children}</div> </div>, document.getElementById('modal-root') as HTMLElement, ); }
바로바로 dialog 태그와 createPortal를 이용하면 된다!
딱봐도 코드가 더 간결해지고 children을 받으면서 쉽게 커스텀도 용이해졌다!
지금이라도 내 게시글을 보는 사람들은 이 방법으로 바꿨으면 좋겠다! (더 좋은 방법이 있으면 말좀요...! ㅎ)
import { createPortal } from "react-dom"; import React, { useRef, useState } from "react"; type ModalProps = { isOpen: boolean; onClose: () => void; children: React.ReactNode; }; const ModalComp = ( <dialog ref={ref} open={isOpen} id={"modal"} className={`absolute left-0 top-0 w-screen h-screen bg-opacity-20 bg-gray-800 ${animation}`} onClick={(e) => { if (e.target === ref.current) { handleClose(); } }} > <article id={"modal-content"} className={"fixed left-1/4 top-1/4 w-1/2 h-1/2 bg-white rounded-lg p-5"} > {children} </article> </dialog> ); return createPortal(ModalComp, document.body); }
다음글이 없습니다.이전글이 없습니다.댓글