본문 바로가기

프로젝트

[해양물류] 모달창 구현 시 UX/접근성/스크린 리더 고려.

 

useModal 사용한 모달창 구현

import { useState } from 'react';

const useModal = () => {
  const [isOpen, setIsOpen] = useState(false);

  const openModal = () => setIsOpen(true);
  const closeModal = () => setIsOpen(false);

  return {
    isOpen,
    openModal,
    closeModal,
  };
};

export default useModal;

기본 모달창 생성.

import React from 'react';
import './Modal.scss';

interface ModalProps {
  isOpen: boolean;
  onClose: () => void;
}

const Modal = ({ isOpen, onClose }: ModalProps) => {
  if (!isOpen) return null;

  return (
    <div className="modal-backdrop" onClick={onClose}>
      <div className="modal-content" onClick={(e) => e.stopPropagation()}>
        <p>아직 작업 중에 있습니다.</p>
        <button className="modal-button" onClick={onClose}>
          확인
        </button>
      </div>
    </div>
  );
};

export default Modal;

 

onClick{(e) => e.stopPropagation()} 을 사용하여 부모 태그의 이벤트가 발생하지 않도록 막음.

근데 생각해보면 button태그만 클릭되면 되는거라 2개의 div는 비인터랙션 태그임.

 

=> 2개의 비인터랙션 div 태그에는 키보드 이벤트 및 role, tab 지원이 필요 없음.

 

1. 접근성 고려

 

  • 직접 키보드 이벤트와 role 지정.
  return (
    <div 
      className="modal-backdrop" 
      onClick={onClose}
      role="button" 
      tabIndex={0}
      onKeyDown={handleKeyDown}
    >
      <div className="modal-content" onClick={(e) => e.stopPropagation()}>
        <p>아직 작업 중에 있습니다.</p>
        <button className="modal-button" onClick={onClose}>
          확인
        </button>
      </div>
    </div>
  );

 - 키보드 이벤트 추가: onKeyDown 이벤트를 추가하여 Enter 또는 Space 키로 모달을 닫을 수 있도록 합니다.
 - 적절한 role 지정: div가 인터랙티브한 요소처럼 작동하므로, role="button"을 추가하여 의미를 명확히 합니다.
 - tabIndex 추가: tabIndex={0}를 추가하여 요소가 탭 키를 통해 포커스를 받을 수 있도록 합니다.

 

  •  button 태그 사용.
  return (
    <button 
      className="modal-backdrop"
      onClick={onClose}
    >
      <div className="modal-content" onClick={(e) => e.stopPropagation()}>
        <p>아직 작업 중에 있습니다.</p>
        <button className="modal-button" onClick={onClose}>
          확인
        </button>
      </div>
    </button>
  );

div태그 대신 button 태그 사용. button 안에 button이기에 이벤트 버블링 주의!

  • dialog 태그 사용
  // 참고: `<dialog>` 요소를 열고 닫을 때 `open` 속성을 직접 다뤄야 함.
  return (
    <dialog open={isOpen} className="modal-dialog" onClick={onClose}>
      <div className="modal-content" onClick={(e) => e.stopPropagation()}>
        <p>아직 작업 중에 있습니다.</p>
        <button className="modal-button" onClick={onClose}>
          확인
        </button>
      </div>
    </dialog>
  );

dialog 태그는 HTML5으로 모달창을 고려한 태그임. 따라서, 접근성을 내장하고 있음. But, 오래된 브라우저에는 지원안됨.

 

  • section, article 사용
  return (
    <section
      className="modal-backdrop"
      onClick={onClose}
      role="dialog"
      tabIndex={0}
      onKeyDown={(e) => {
        if (e.key === 'Enter' || e.key === ' ') {
          onClose();
        }
      }}
    >
      <div className="modal-content" onClick={(e) => e.stopPropagation()}>
        <p>아직 작업 중에 있습니다.</p>
        <button className="modal-button" onClick={onClose}>
          확인
        </button>
      </div>
    </section>
  );

모달 내용이 복잡하고 의미 있는 경우 사용. role 및 키보드 이벤트 직접 추가해줘야 함.

 

결론: 

  • 단순한 모달 기능을 빠르게 구현하고 싶다면 <button> 태그를 사용하는 것이 가장 간단하고 오류 없이 작업할 수 있습니다.
  • 더 의미론적이고 표준적인 접근을 원한다면 <dialog> 태그를 사용할 수 있습니다. 다만, 브라우저 호환성을 고려해야 합니다.
  • 내용이 복잡하고 의미적으로 구분이 필요한 경우 <section> 또는 <article> 태그를 사용하면서 적절한 role과 키보드 이벤트를 추가하는 것이 좋습니다.

 

2. 스크린 리더 고려

 

  • role과 aria 속성 추가: 모달의 의미를 스크린 리더에게 알리고, 제목과 내용을 참조하도록 개선.
  • 배경 스크롤 잠금: 모달이 열릴 때 배경 페이지의 스크롤을 막아 사용자 경험을 개선.
  • 포커스 트랩 추가: 탭 키를 사용해도 포커스가 모달 내부에 머무르도록 개선.
  • Escape 키로 모달 닫기: Escape 키로 모달을 닫을 수 있도록 키보드 접근성 개선.

=> 모달이 접근성 표준에 부합하고 스크린 리더에 적절한 정보를 제공하며, 포커스 제어를 통해 사용자 경험도 향상됨.

 

 

😎😎😎

추천 학습 및 작업 순서
- 기본 접근성 원칙 이해: role과 aria 속성에 대해 배우는 것부터 시작하세요. role="button", aria-label 등 간단한 속성을 추가하는 것만으로도 접근성이 크게 개선될 수 있습니다.
- 키보드 접근성 연습: 모달을 만들고 탭 키로 요소를 순회하는 것부터 해보세요. 키보드만으로 모든 기능을 사용할 수 있도록 하는 것이 첫 번째 목표입니다.
- 스크린 리더 테스트 도구 사용: Chrome의 Lighthouse 같은 접근성 테스트 도구를 활용하여 코드의 접근성 문제를 찾아보세요. 필요한 경우 무료 스크린 리더 소프트웨어인 NVDA(Windows)나 VoiceOver(Mac)을 사용해보는 것도 추천합니다.

 

💯💯💯

신입이 집중할 수 있는 핵심 포인트
- 키보드 인터랙션: 탭, Enter, Esc 키 등 키보드만으로 모달을 사용할 수 있게 하는 것에 먼저 집중하세요.
- 포커스 관리: 모달이 열릴 때 첫 번째 포커스 가능한 요소로 포커스를 이동시키고, 닫힐 때 원래 포커스 위치로 돌아가도록 관리하세요.
- 스크린 리더 인디케이션: role="dialog"와 aria-labelledby 같은 속성을 추가해 스크린 리더가 제대로 모달을 설명할 수 있게 하는 간단한 것부터 시작하세요.