애드블럭 종료 후 사이트를 이용해 주세요.

ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Portal만 쓰시나요? HTML 표준 Dialog, Popover API 알아보기
    Tip 2025. 6. 7. 19:51
    728x90
    반응형

    React를 개발하다 보면 대부분 Portal을 사용해서 모달이나 팝업을 구현합니다.

    오늘은 Portal이 아닌 HTML의 표준 요소인 Dialog, Popover API를 알아보고 Portal이 아니라 Dialog나 Popover를 사용하는 경우에 대해서도 알아보도록 하겠습니다.

    1. Portal

    Portal은 컴포넌트 트리 바깥으로 DOM 요소를 렌더링 할 수 있게 하는 기술입니다.
    React에서는 ReactDOM.createPortal로 구현합니다.

    주로 모달이나 팝업처럼 현재 DOM 계층과 독립적인 UI 레이어를 만들고 싶을 때 많이 사용합니다.

    • z-index 이슈가 복잡한 경우
    • 모달이 부모 컴포넌트의 overflow나 transform 등에 영향을 받지 않게 하고 싶을 때
    • 레이아웃과 별도로 레이어 UI를 관리하고자 할 때
    import { createPortal } from 'react-dom';
    
    export default function CommonModal() {
      const title = 'CommonModal';
      return createPortal(
        <div
          style={{
            position: 'fixed',
            top: '50%',
            left: '50%',
            transform: 'translate(-50%, -50%)',
            background: '#fff',
            padding: '2rem',
            boxShadow: '0 0 10px rgba(0,0,0,0.3)',
            zIndex: 1000
          }}
        >
          {title}
        </div>,
        document.body
      );
    }

     

    Portal은 보통 document.body에 렌더링 합니다.

    그래서 모달 등 고정 레이어를 구현할 때 유용하고, z-index 충돌이나 CSS 문제를 회피할 수 있습니다.

    Portal 모달을 만들 때는 body에 overflow: hidden 처리를 통해 스크롤을 막아주고, 
    포커스 트랩을 넣어 접근성을 챙기는 것이 좋습니다.

     

    2. Dialog

    <dialog>는 HTML 표준 요소입니다.
    따라서 별도 라이브러리 없이 모달 창을 구현할 수 있고, 기본적인 접근성 기능도 제공합니다.

    • 간단한 모달을 빠르게 만들고 싶을 때
    • 접근성(스크린 리더 대응, 키보드 지원 등)이 중요한 경우
    • React가 아닌 순수 HTML 기반 기능을 쓰고 싶을 때
    'use client';
    
    import { useRef } from 'react';
    
    export default function ExamDialog() {
      const dialogRef = useRef<HTMLDialogElement>(null);
    
      return (
        <div>
          <dialog ref={dialogRef}>
            <p>모달 창 입니다.</p>
            <button onClick={() => dialogRef.current?.close()}>닫기</button>
          </dialog>
    
          <button onClick={() => dialogRef.current?.showModal()}>열기</button>
        </div>
      );
    }

    주의점

    • Safari는 <dialog>를 아직 기본 지원하지 않으므로 polyfill이 필요합니다.
    • 기본 포커스 트랩, 스크롤 락은 있지만 고급 커스터마이징을 원한다면 직접 추가 구현이 필요합니다.
    Dialog는 접근성이 내장되어 있고 구현이 빠르기 때문에, 간단한 안내 팝업이나 설정 모달 등에 적합합니다.
    하지만 커스텀 애니메이션, 포지션 커스터마이징이 필요하다면 Portal 기반 모달이 더 유연합니다.

    3. Popover API

    Popover API는 HTML 표준에서 새로 등장한 기능입니다.
    툴팁, 작은 팝업 메뉴처럼 요소와 연결된 작은 팝업 UI를 쉽게 구현할 수 있어요.

    • 버튼과 연결된 팝업 메뉴 구현 시 (ex. 컨텍스트 메뉴, 사용자 설정 메뉴 등)
    • 툴팁처럼 가벼운 UI 요소를 만들고 싶을 때
    • 위치 자동 조정 기능을 기본으로 활용하고 싶을 때
    <button popovertarget="myPopover">열기</button>
    <div id="myPopover" popover>
      Popover 내용
    </div>

    주의점

    • 브라우저 지원이 완전하지 않음 → 최신 Chrome/Edge는 지원, Safari는 진행 중, Firefox는 실험적 기능으로 사용 가능
    • Popover는 상대적으로 경량 팝업에 적합하고, 복잡한 상태 관리나 모달 기능을 대체하긴 어렵습니다.

    개인적 선택 기준

    React에서 사용하는 대부분의 경우 Portal 가장 많이 사용되지만, 다음 상황에서는 Portal 외의 방법을 고려하는 것이 좋습니다.

    • 접근성과 기본 기능이 중요할 때 (Dialog)
      내장된 접근성 기능과 키보드 지원이 필수적일 때는 <dialog> 요소를 사용하는 것이 효율적입니다.
      단, Safari 지원이나 커스텀이 어려운 점을 감안해야 됩니다.
    • 버튼과 직접 연결된 간단한 UI 구현 시 (Popover API)
      툴팁, 작은 메뉴와 같이 특정 요소에 연결된 UI는 Popover API를 사용하는 것이 더 간편하고 효율적입니다.
      앞으로는 메뉴 등의 ul li 요소를 대체하거나, 간단한 옵션 팝업 구현에 많이 쓰일 것으로 기대되지만, 지금 시점에서는 브라우저 호환성 등을 고려해야 됩니다.
    반응형

    댓글

Designed by Tistory.