DropDown 구현

이지·2024년 3월 30일
0

쇼핑몰 프로젝트에서 마이페이지를 클릭했을 때, 마이페이지로 갈지, 로그아웃을 할지 선택할 수 있는 드롭다운을 구현하였습니다.

드롭다운

      <S.Nav>
        <ShoppingCartLink />
        <MyPageLink />
        {isOpenDropDown && (
          <S.DropDownBox
            isMobile={isMobile}
            onClick={() => setIsOpenDropDown(false)}
            ref={dropDownRef}
          >
            <Link to="/mypage">마이페이지</Link>
            <button
              type="button"
              onClick={handleLogout}
            >
              로그아웃
            </button>
          </S.DropDownBox>
        )}
      </S.Nav>

드롭다운을 구현하면서 추가적으로 구현한 부분은 다음과 같습니다.

  • 외부를 클릭했을 때, 드롭다운이 안보이도록 처리하기
  • 접근성 고려하기

외부를 클릭했을 때, 드롭다운이 안보이도록 처리

  • 이를 구현할 때 드롭다운 전체 영역에 ref를 추가해야 합니다.
useEffect(() => {
  // 마우스 이벤트가 드롭다운 메뉴 영역 바깥에 있는지 확인하여, 
  // 드롭다운이 열려있고 사용자가 드롭다운 바깥을 클릭했다면 드롭다운을 닫도록 설정
    const handleClickOutside = (event: MouseEvent) => {
      if (
        dropDownRef.current &&
        !dropDownRef.current.contains(event.target as Node)
      ) {
        setIsOpenDropDown(false);
      }
    };
	// 문서 전체에 대해 마우스 다운 이벤트를 감지하고, 이벤트가 발생할 때마다 handleClickOutside 함수를 실행
    document.addEventListener("mousedown", handleClickOutside);
	// return 문에서는 useEffect의 cleanup 함수를 정의
	// 컴포넌트가 사라질 때 이벤트 리스너를 제거하여 메모리 누수를 방지
    return () => {
      document.removeEventListener("mousedown", handleClickOutside);
    };
  }, [isOpenDropDown, setIsOpenDropDown]);

여기까지 구현했을 때, tab을 통해 드롭다운이 열릴 경우 드롭다운 영역으로 focus가 이동하는지 확인해본 결과 같은 nav에 속한 첫번째 장바구니로 focus가 이동하였습니다. 드롭다운 영역으로 focus가 이동하도록 하겠습니다.

드롭다운 영역으로 focus 이동하기

  useEffect(() => {
    if (isOpenDropDown) {
      dropDownRef.current.querySelector("a").focus();
    }
  }, [isOpenDropDown]);
  • 드롭다운의 마이페이지 링크에 focus가 이동하도록 하였습니다.

드롭다운이 열렸을 때, 모달처럼 tab 키를 눌러도 해당 영역을 벗어나지 않도록 추가로 설정해주었습니다. 드롭다운에서 벗어나고 싶은 경우엔 esc를 눌러 나갈 수 있도록 했습니다.

const handleFocusDropDown = (e: React.KeyboardEvent) => {
    if (!e.shiftKey && e.keyCode === 9) {
      e.preventDefault();
      dropDownRef.current.querySelector("a").focus();
    }
  };

useEffect(() => {
    const escDropDownClose = (e: KeyboardEvent) => {
      if (e.keyCode === 27) {
        setIsOpenDropDown(false);
      }
    };
    document.addEventListener("keydown", escDropDownClose);
    return () => {
      document.removeEventListener("keydown", escDropDownClose);
    };
  }, [isOpenDropDown, setIsOpenDropDown]);

...
    
return (
  ...
  <S.Nav>
        <ShoppingCartLink />
        <MyPageLink />
        {isOpenDropDown && (
          <S.DropDownBox
            isMobile={isMobile}
            onClick={() => setIsOpenDropDown(false)}
            ref={dropDownRef}
          >
            <Link to="/mypage">마이페이지</Link>
            <button
              type="button"
              onClick={handleLogout}
              onKeyDown={handleFocusDropDown} //❗️
            >
              로그아웃
            </button>
          </S.DropDownBox>
        )}
      </S.Nav>
	...
)

드롭다운의 마지막 아이템까지 확인했을 때 다른 사이트의 경우 어떻게 처리하는지 궁금해서 찾아본 결과 쿠팡에서는 드롭다운 영역을 유지하지 않았습니다. (벨로그에서도 드롭다운 메뉴를 눌렀을때 유지를 안하는..)

드롭다운 영역을 유지하는 것을 뺄까 고민했지만, 위의 프로젝트의 경우 마이페이지를 클릭했다면 마이페이지로 이동하거나 로그아웃을 위해 클릭한 것이라 생각하여 일단은 드롭다운 영역에서 벗어나지 않도록 하는 것으로 결정하였습니다.

https://www.youtube.com/watch?v=h82dE7YHg4Y
위의 유튜브 영상은 드롭다운의 접근성 개선을 진행하는 영상입니다.
이 영상에서는 tab키가 아닌 화살표 위, 아래 키를 통해 드롭다운 내의 아이템을 이동할 수 있도록 구현되어 있습니다.
다른 사이트의 드롭다운을 확인했을 때, tab을 사용하거나 화살표 키를 통해 이동하는 2가지 방법이 있는데 둘 중 선택해서 진행하면 될 것 같습니다.

0개의 댓글

관련 채용 정보