[FEATURE] 상품후기/문의 팝업창 접근성 고려하기
SeoMiYoung opened this issue · comments
🌳 작업 브랜치
feat/#212
👀 참고 이슈
- #212
=> 맥락이 거의 비슷합니다. 위의 이슈에서 자세히 서술해놓았으니, 참고하세요.
📝 TASK 개요
[STEP1] 팝업창이 딱 떴을 때, 초점이동이 팝업창 내부로 이동해야 함
Before...(팝업창이 떠도, 팝업창 외부에서 초점 이동이 됨)
해결과정...
우선, 모달 전체창을 참조하는 modalRef를 생성한다.
const modalRef = useRef(); // 모달 전체를 참조
그리고, 모달 전체를 감싸는 <article>
태그에 modalRef를 연결해준다.
<article
className={styles.detailPopUpWrap}
ref={modalRef}
tabIndex="-1"
>
=> 주의해야될 점이, tabIndex를 넣어주지 않으면, article태그 자체는 focus를 받을 수 없음. 따라서, 모달창 전체에 focus를 주기 위해서는 꼭 tabIndex를 설정해줘야 함!
그리고, 다음 코드를 추가해서, 모달창이 열리는 순간, 모달창에 포커스가 되도록 설정한다.
// 모달창이 뜰 때, 포커스
useEffect(() => {
modalRef.current.focus();
}, []);
After...
[STEP2] 모달창이 떠 있을 때, 초점은 계속 모달창 내부에서 순환해야 함
Before...
계속해서 Tab키를 누름에도 불구하고, 모달창 내에서 포커스 순환이 이루어지고 있지 않음
해결과정...
이벤트 핸들러 연결
const handleModalKeyEvent = (e) => {
const firstFocusableElement = smallCloseBtnRef.current;
let lastFocusableElement;
if(registrationBtnRef.current.disabled == true) { // 등록버튼이 disabled라면,
lastFocusableElement = cancelBtnRef.current;
}
else { // 등록버튼이 활성화 상태라면
lastFocusableElement = registrationBtnRef.current;
}
// Tab, Shift키 누른 여부를 저장
const isTabPressed = (e.key === 'Tab');
const isShiftPressed = e.shiftKey;
if(!isTabPressed) { // Tab키를 누르지 않은 경우
console.log('Tab이 아닙니다.');
return;
}
if(isShiftPressed) { // Shift+Tab 누른 경우
// document.activeElement는 현재 focus요소를 가리킨다
if(document.activeElement === firstFocusableElement) {
lastFocusableElement.focus();
e.preventDefault();
}
}
else { // Shift를 누르지 않고, tab키만 눌렀을 경우
if(document.activeElement === lastFocusableElement) {
firstFocusableElement.focus(); // 다시 첫번째 요소로 focus
e.preventDefault();
}
}
}
단, 메인모달창, 카트모달창과 다르게, focusable한 요소들을 배열로 굳이 관리하고 있지 않음.
그냥 굳이 그렇게 관리 안해도 될 것 같아서 굳이 배열을 생성하지 않기로 함.
단, 순환을 할 때, '첫번째 요소'와 '마지막 요소'는 구분해야하므로, focusable한 요소들을 참조할 수 있는 ref는 사용함.
const smallCloseBtnRef = useRef(); // X버튼
const cancelBtnRef = useRef(); // 취소 버튼
const registrationBtnRef = useRef(); // 등록 버튼
참고로, disabled상태는 focus를 받을 수 없으므로, 등록 버튼이 disabled인 경우, 마지막 요소의 경우 대상이 달라짐.
따라서, if, else문으로 등록 버튼의 disabled상태에 따라 다른 마지막 요소를 부여함.
After...
[STEP3] textarea에 tab키로 focus가 될 때 placeholder가 사라지지 않는 현상 해결하기
Before...
해결과정...
<textarea>
태그 부분에 onFocus 이벤트 핸들러를 연결해줌
After...
[STEP4] 메인모달창 내에서 포커스 이동이 되다가, 갑자기 외부영역을 클릭하면, 외부영역이 포커스가 잡히는 점 해결하기
- 참고한 커밋: 1ed104b
ProductDetailPopUp.jsx
에서 다음 코드들 추가
import { darkFilterFocusState } from '../../store/darkFilterState';
const setDarkFilterFocus = useSetRecoilState(darkFilterFocusState);
// 모달창이 뜰 때, 포커스
useEffect(() => {
modalRef.current.focus();
setDarkFilterFocus(modalRef.current);
}, []);
[STEP5] 모달창 전체를 감싸는 태그에 추가한 속성들 살펴보기
- 관련 이슈의 [STEP6]참고: #212
<article
className={styles.detailPopUpWrap}
ref={modalRef}
tabIndex="-1"
onKeyDown={handleModalKeyEvent}
role="dialog"
aria-modal="true"
aria-label={`${title} 모달창이 열렸습니다.`}
>
[STEP6] 비밀글 관련, 문제 발생 해결하기..(Q/A질문 등록)
문제 내용: 상품 문의 팝업창의 경우, '비밀글'에 focus가 되지 않는 현상 발생
- 관련 이슈 질문글: yamoo9/likelion-FEQA#300
Secret.module.scss
수정
input[type="checkbox"] {
//display: none;
appearance: none; // 체크박스 input요소의 기본 UI가 보이지 않게 하기
position: absolute; //input요소가 영역을 차지하지 않게끔 붕 띄우기
padding: 12px;
}
✅ To Do 및 진행상황
- [STEP1] 팝업창이 딱 떴을 때, 초점이동이 팝업창 내부로 이동해야 함
- [STEP2] 모달창이 떠 있을 때, 초점은 계속 모달창 내부에서 순환해야 함
- [STEP3] textarea에 tab키로 focus가 될 때 placeholder가 사라지지 않는 현상 해결하기
- [STEP4] 메인모달창 내에서 포커스 이동이 되다가, 갑자기 외부영역을 클릭하면, 외부영역이 포커스가 잡히는 점 해결하기
- [STEP5] 모달창 전체를 감싸는 태그에 추가한 속성들 살펴보기
- [STEP6] 비밀글로 설정하기에 포커스 가능하게 하기