모달 구현 시 고려해야 할 사항

yarnmiyarnmi
3 min read

들어가며

최근에 UI를 직접 구현하는 스터디에 참여하게 되었다. 첫 번째 주제로 모달 UI를 다루게 되었고, 간단한 모달을 구현하며 모달의 기능과 동작 방식을 살펴보았다. 이 과정에서 모달을 구현할 때 고려해야 할 부분을 알게 되어 정리해 보았다.

모달이란?

모달은 페이지 주요 콘텐츠에 대한 추가 정보를 제공하거나 사용자의 액션을 유도하기 위해서 페이지 위에 오버레이 형태로 표시되는 UI 컴포넌트다.

모달의 일반적인 특징

  • 유저가 버튼을 클릭하면 모달이 나타난다.

  • 모달은 부모 컴포넌트의 구조와 스타일에 영향을 받지 않도록 독립적으로 동작해야 한다.

  • 모달은 배경을 흐릿하게(dimmed) 처리하여 사용자의 집중도를 높인다.

이제 이번에 간단한 모달 구현했을 때 고려했던 부분을 살펴보자.

간단한 모달 구현시 고려했던 사항들

  1. createPortal을 사용한 렌더링

    • createPortal을 사용하여 모달이 DOM 계층 구조를 벗어나 document.body에 렌더링되도록 처리했다. 이 방식으로 부모 컴포넌트에 영향받지 않고 독립적으로 동작할 수 있었다.
  2. Controlled 컴포넌트 방식 적용

    • 모달의 상태(open, onClose)를 부모 컴포넌트에서 전달받도록 설계했다. 부모의 상태 변경을 그대로 사용해서 일관되게 모달을 제어할 수 있도록 했다.
  3. 컴포지션 패턴 적용

    • 모달 내부에서 컨텐츠를 유연하게 전달하기 위해서 컴포지션 패턴을 사용했다. props drilling 없이 children 을 통해 원하는 내용을 주입할 수 있도록 했다 .

    • 모달 내부 구조

      • Modal

      • Modal.Header

      • Modal.Body

      • Modal.Footer

  4. Context API를 활용한 상태 관리

    • 모달 내부의 자식 컴포넌트가 깊은 경우, onClose 함수를 전달하려면 여러 단계의 props drilling이 발생하게 된다. Context API를 사용해서 Provider를 추가하고, 하위 컴포넌트가 모달 상태에 직접 접근할 수 있도록 했다.
  5. 이벤트 핸들링 : ESC키와 모달 배경 클릭 감지

    • 모달 배경 클릭하거나 ESC 키를 눌렀을 때 모달창이 닫히도록 useKeyDown 훅을 구현했다.
  1.   const useKeyDown = (key: string, onClose: () => void): void => {
        useEffect(() => {
          const handleKeyDown = (e: KeyboardEvent) => {
            if (e.key === key) onClose();
          };
    
          document.addEventListener("keydown", handleKeyDown);
          return () => {
            document.removeEventListener("keydown", handleKeyDown);
          };
        }, [key, onClose]);
      };
    

기본적인 모달을 구현했지만, 모달은 트리거 영역과 컨텐츠 영역으로 나눠져서 더 고려해야 할 부분이 많다는 걸 알게 되었다. 추가적으로 고려해야 할 부분을 살펴보자.

추가적으로 더 고려해야 하는 부분

  1. 모달 컨텐츠에 대한 maxHeight 적용

    • 모달 컨텐츠가 긴 경우, 모달 자체가 페이지를 벗어날 수 있기 때문에 모달창 내부에서 스크롤이 가능하도록 maxHeight 속성을 적용해야 한다.
  2. 키보드 인터렉션 및 포커스 관리

    • tab 키 클릭 시 포커스가 모달 내부에서만 순환하도록 처리해야 한다.

    • 모달이 열릴 때, 모달을 열었던 요소에 대한 참조를 저장해 둬서 모달이 닫힐 때, 참조된 요소로 포커스가 복원되어야 한다.

  3. 접근성 참고 링크

  4. 애니메이션 및 트랜지션 적용

    • 모달은 조건부 렌더링(open 상태에 따라 mount/unmount) 되기 때문에 부드러운 전환 효과가 필요하다.

    • 배경(dimmed)과 콘텐츠의 트랜지션을 별도로 적용하려면 요소를 분리하여 렌더링해야 한다.

    • 모달의 open 상태와 싱크를 맞춘 별도의 상태 관리가 필요할 수도 있다.

  5. 중첩 모달 관리

    • 여러 개의 모달이 열릴 경우, ESC 키 입력 시 최상위 모달만 닫혀야 한다.

    • 하위 모달을 닫을 경우, 상위 모달까지 모두 닫혀야 한다.

마무리하며

모달은 단순한 UI 요소가 아니라, 접근성, 상태 관리, 애니메이션 등 다양한 고려 사항이 필요한 컴포넌트다. 추가로 고려해야 하는 부분을 알게 되었으니, 간단히 구현한 모달에 하나씩 적용해보려 한다.

참고 문서

Radix UI - Dialog

0
Subscribe to my newsletter

Read articles from yarnmi directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

yarnmi
yarnmi