키보드 이벤트 타입은 총 3가지가 있다.
그 중에서도 가장 keydown 이벤트를 활용하여 키보드 방향키 + Enter 키로 옵션을 선택하는 기능을 구현할 것이다.
1. tabIndex 속성 설정
이벤트를 받으려는 HTML 요소에 tabIndex 속성을 설정하고, (그래야 div 요소가 포커스를 받을 수 있다.)
SelectorBox 컴포넌트에 keydown 이벤트를 바인딩한다.
- tabIndex : 요소가 포커스 가능함을 의미
- SelectorBox는 div(비 대화형 콘텐츠)이기 때문에 tabindex = -1 이 기본값이다.
- 이를 키보드 탐색으로도 접근 가능하도록 tabindex = 0 으로 변경해준다.
2. onKeyDown 이벤트 핸들러
- 아래 방향키
- 한 칸 아래 요소로 이동
- 맨 마지막 요소일 경우 가장 처음으로 이동
- 위 방향키
- 한 칸 위 요소로 이동
- 맨 처음 요소일 경우 가장 마지막으로 이동
const findIndexDown = (prevIndex: number | null) => {
// prevIndex가 없거나 마지막 요소일 때 처음 항목을 focus
if (prevIndex === null || prevIndex === options.length - 1) return 0;
else return prevIndex + 1;
};
const findIndexUp = (prevIndex: number | null) => {
// prevIndex가 없거나 첫 번째 요소일 때 마지막 항목을 focus
if (prevIndex === null || prevIndex === 0) return options.length - 1;
else return prevIndex - 1;
};
const handleKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {
switch (e.key) {
case "ArrowDown":
setFocusedIndex((prevIndex) => findIndexDown(prevIndex));
return;
case "ArrowUp":
setFocusedIndex((prevIndex) => findIndexUp(prevIndex));
return;
case "Enter":
console.log("Enter~");
return;
}
};
3. hover한 item에 focus 할당
OptionItem 컴포넌트에 onMouseOver 이벤트 핸들러를 바인딩해서 hover한 item도 키보드 방향키로 선택한 아이템처럼 focus 스타일링을 해준다.
<CommonOptionItem
key={idx}
onClick={() => handleClick(option)}
onMouseOver={() => setFocusedIndex(idx)}
>
4. 옵션 리스트 다시 열리면 focus 값 초기화
handlePopup 함수에서 팝업 열릴 때 초기화를 실행해준다.
5. Enter 시 선택
case "Enter":
if (typeof focusedIndex === "number") {
onChange(options[focusedIndex]);
handlePopup();
}
return;
조건을 if (focusedIndex) 로 할 경우, 인덱스가 0일 때도 false를 가지게 되므로 fucusedIndex의 타입과 비교를 해줬다.
6. 선택된 값이 있으면 해당 값에 focus
// 선택된 아이템이 있을 경우 해당 아이템 focus
const selectedIndex = () => {
const newIndex = options.findIndex((option) => option === item);
if (newIndex !== -1) setFocusedIndex(newIndex);
};
제법 SelectBox 같아지는 중....!
'React' 카테고리의 다른 글
[ React ] CommonTable 컴포넌트 기본 구현 (정렬, 체크박스, 스크롤 등) (0) | 2024.07.16 |
---|---|
[ React ] DatePicker, SelectBox의 팝업을 createPortal로 변경 (0) | 2024.07.12 |
[ React ] input 태그의 placeholder로 icon 사용하기 (0) | 2024.07.10 |
[ React ] 검색 가능한 SelectBox 컴포넌트 구현 (0) | 2024.07.04 |
[ React ] 기본 SelectBox 컴포넌트 구현 (1) | 2024.07.03 |