Skip to main content

react앱에서 dialog태그로 모달 만들고 body 스크롤 막기

· 3 min read
rowanna
Front End Engineer
Hits

모달을 만들기 위해 dialog 태그를 사용해보고 CSSbody 태그의 스크롤 막기 작업도 해봅시다.

🔥 들어가며

이번에 about페이지를 개발하면서 modal을 만들 일이 있었습니다.
다음 UI를 클릭하면 모달이 뜨게끔 개발하고 싶었는데요, alt text ASAC 07기에서 배운 dialog 태그를 이용해서 작업했는데,
좀 더 나은 UX를 위해 추가적으로 작업해야할 것들이 있어서
방법론처럼 정리해서 알아두면 좋을 것 같아 기록해보려 합니다.

🔥 dialog 적용하기

우선 dialog를 적용해봅시다.
dialog에 데이터는 다음과 같은 플로우로 전달됩니다.

1. 클릭한 요소에서 openDialog을 할 때 함수 파라미터로 work를 보냄.

2. 그 workdialogData 관리함.

3. openDialog 했을 때 setDialogData로 설정해줌.

index.tsx
import { projects } from "../../../static/json/projects.json";

export default function About(): ReactNode {
const dialogRef = useRef(null);
const [dialogData, setDialogData] = useState<MyObject | null>({});
const openDialog = (e, works) => {
const current = dialogRef.current ?? document.createElement("dialog");

setDialogData(() => works);

if (!current) return;

current.showModal();
};
const closeDialog = (e) => {
const current = dialogRef.current ?? document.createElement("dialog");

if (!current) return;
if (e.target.nodeName === "DIALOG" || e.target.nodeName === "BUTTON") {
current.close();
}
};

return (
<div>
{projects.map((project) => (
<div
key={project.id}
onClick={(e) => openDialog(e, project)}
className={styles.work_card_item}
>
<button>
<div
style={{
background: `url(${project.backgroundImgUrl}) no-repeat center/cover`,
width: "100%",
height: "300px",
}}
></div>
<div className={styles.item_desc}>
<h3>{project.title}</h3>
<p>{project.short_desc}</p>
<p>{project.date}</p>
<div className={styles.tag_wrap}>
{project.tags.map((tag) => (
<span>{tag}</span>
))}
</div>
<div className={styles.type}>
<span>{project.type}</span>
</div>
</div>
</button>
</div>
))}
</div>
);
}

4. state dialogData 로 접근하여 dialog에 뿌려줌.

<dialog
onClick={(e) => closeDialog(e)}
className={styles.about_dialog}
ref={dialogRef}
>
<div
style={{
background: `url(${dialogData.backgroundImgUrl}) no-repeat center/cover`,
width: "100%",
height: "300px",
}}
></div>
<div className={styles.dialog_item_desc}>
<h1>{dialogData.title}</h1>
<p>{dialogData.short_desc}</p>
<p>{dialogData.long_desc}</p>
<p>{dialogData.date}</p>
<div className={styles.tag_wrap}>
{dialogData?.tags?.map((tag) => (
<span>{tag}</span>
))}
</div>
<div className={styles.type}>
<span>{dialogData.type}</span>
</div>
</div>
<button onClick={(e) => closeDialog(e)}>Close</button>
</dialog>

다 적용된 모습은 다음과 같습니다.

하지만 gif에서 보면 알 수 있듯이 뒷 배경이 스크롤되는 걸 볼 수 있죠. 이는 예전에는 javascript로 설정해주어야 했습니다. 하지만 이는 css 만으로도 개선할 수 있습니다.

🔥 UX 개선하기

뒷 배경이 스크롤되는 문제는 css만으로도 개선할 수 있습니다.

body:has(dialog[open]) {
overflow: hidden !important;
}