코드도보통지

4관문. Portal Focus Trap

관문 4 / 7

모달이 열렸을 때 Tab 키 포커스가 모달 내부를 순환하도록 Focus Trap을 구현하라.

📖 이론 비급

Focus Trap: 접근성의 기본

모달이 열렸을 때 Tab 키가 배경 컨텐츠로 이동하면 스크린 리더 사용자가 모달 밖을 인식하지 못할 수 있다.

구현 방법:

  1. 모달 내 포커스 가능한 엘리먼트를 querySelectorAll로 수집
  2. keydown 이벤트에서 Tab/Shift+Tab 시 첫/마지막 엘리먼트로 포커스를 이동
  3. 모달 마운트 시 첫 번째 엘리먼트로 포커스 이동

⚔️ 수련 코드

import { useRef, useEffect, useState } from 'react';

function Modal({ onClose }) {
  const modalRef = useRef(null);

  useEffect(() => {
    // TODO: 모달 내부의 focusable 엘리먼트를 수집하고
    // Tab/Shift+Tab 시 순환하도록 keydown 핸들러를 추가하라
    // 마운트 시 첫 번째 포커스 가능 요소에 focus()
    const focusable = modalRef.current?.querySelectorAll(
      'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
    );
    focusable?.[0]?.focus();
  }, []);

  return (
    <div ref={modalRef} role="dialog" style={{ border: '2px solid', padding: 24 }}>
      <h2>모달</h2>
      <input placeholder="이름" />
      <input placeholder="이메일" />
      <button onClick={onClose}>닫기</button>
    </div>
  );
}

export default function App() {
  const [open, setOpen] = useState(false);
  return (
    <div>
      <button onClick={() => setOpen(true)}>모달 열기</button>
      {open && <Modal onClose={() => setOpen(false)} />}
    </div>
  );
}