의미론적 HTML 요소의 DOM 위치에서 제공하는 기본 탭 순서는 편리하지만 탭 순서를 수정해야 하는 경우가 있을 수 있습니다. HTML에서 요소를 이동하는 것이 이상적이지만 불가능할 수도 있습니다. 이 경우 tabindex
HTML 속성을 사용하여 요소의 탭 위치를 명시적으로 설정할 수 있습니다.
tabindex
는 모든 요소에 적용할 수 있지만 모든 요소에 유용한 것은 아니며 정수 값의 범위를 사용합니다. tabindex
를 사용하면 포커스 가능한 페이지 요소의 명시적 순서를 지정하고, 탭 순서에 포커스할 수 없는 요소를 삽입하고, 탭 순서에서 요소를 삭제할 수 있습니다. 예를 들면 다음과 같습니다.
tabindex="0"
: 요소를 자연스러운 탭 순서에 삽입합니다. Tab을 눌러 요소에 포커스를 둘 수 있으며, 요소의 focus()
메서드를 호출하여 요소에 포커스를 둘 수 있습니다.
tabindex="-1"
: 자연스러운 탭 순서에서 요소를 삭제하지만 요소의 focus()
메서드를 호출하여 여전히 요소에 포커스를 둘 수 있습니다.
tabindex="5"
: 0
보다 큰 tabindex는 해당 요소를 자연스러운 탭 순서의 맨 앞으로 가져옵니다. tabindex가 0
보다 큰 요소가 여러 개 있는 경우 탭 순서는 0보다 큰 가장 낮은 값에서 시작하여 위로 올라갑니다.
특히 헤더, 이미지, 기사 제목과 같은 입력이 아닌 요소의 경우 더욱 그렇습니다. 가능한 경우 DOM 시퀀스가 논리적 탭 순서를 제공하도록 소스 코드를 정렬하는 것이 좋습니다. tabindex
를 사용하는 경우 버튼, 탭, 드롭다운, 텍스트 입력란과 같은 맞춤 대화형 컨트롤로 제한하세요. 즉, 사용자가 입력을 제공할 것으로 예상하는 요소입니다.
상호작용형 콘텐츠에만 tabindex
를 추가하세요. 핵심 이미지와 같이 콘텐츠가 중요한 경우에도 스크린 리더 사용자는 포커스를 추가하지 않고도 콘텐츠를 이해할 수 있습니다.
페이지 수준에서 포커스 관리
원활한 사용자 환경을 위해 tabindex
가 필요한 경우가 있습니다. 예를 들어 모든 콘텐츠가 동시에 표시되지 않는 다양한 콘텐츠 섹션이 있는 강력한 단일 페이지를 빌드하는 경우입니다. 이는 탐색 링크가 페이지 새로고침 없이 표시되는 콘텐츠를 변경할 수 있음을 의미합니다.
이 경우 선택된 콘텐츠 영역을 식별하고 -1
의 tabindex
를 지정한 후 focus
메서드를 호출합니다. 이렇게 하면 콘텐츠가 자연스러운 탭 순서로 표시되지 않습니다. 포커스 관리라고 하는 이 기법은 사용자가 인식하는 컨텍스트를 사이트의 시각적 콘텐츠와 동기화합니다.
구성요소에서 포커스 관리
경우에 따라 맞춤 구성요소와 같이 컨트롤 수준에서 포커스를 관리해야 합니다.
예를 들어 select
요소는 기본 포커스를 받을 수 있지만, 포커스가 이동한 후에는 화살표 키를 사용하여 선택 가능한 추가 옵션을 표시할 수 있습니다.
맞춤 select
요소를 빌드하는 경우 키보드 사용자가 컨트롤과 계속 상호작용할 수 있도록 해당 동작을 복제하는 것이 중요합니다.
어떤 키보드 동작을 구현해야 할지 알기 어려울 수 있습니다. Accessible Rich Internet Applications (ARIA) 작성 관행 가이드에는 구성요소 유형과 지원되는 키보드 작업 종류가 나열되어 있습니다.
라디오 버튼과 유사하지만 모양과 동작에 고유한 접근 방식을 적용한 맞춤 요소를 작업하고 있을 수도 있습니다.
<radio-group>
<radio-button>Water</radio-button>
<radio-button>Coffee</radio-button>
<radio-button>Tea</radio-button>
<radio-button>Cola</radio-button>
<radio-button>Ginger Ale</radio-button>
</radio-group>
필요한 키보드 지원을 확인하려면 ARIA 작성 관행 가이드를 참고하세요. 섹션 2에는 라디오 그룹의 특성 표를 비롯한 디자인 패턴 목록이 포함되어 있습니다. 이는 새 요소와 가장 유사한 기존 구성요소입니다.
지원해야 하는 일반적인 키보드 동작 중 하나는 위/아래/왼쪽/오른쪽 화살표 키입니다. 새 구성요소에 이 동작을 추가하기 위해 이동 가능한 tabindex라는 기법을 사용합니다.
이동 가능한 tabindex는 현재 활성 상태인 항목을 제외한 모든 하위 항목에 tabindex
을 -1로 설정하여 작동합니다.
<radio-group>
<radio-button tabindex="0">Water</radio-button>
<radio-button tabindex="-1">Coffee</radio-button>
<radio-button tabindex="-1">Tea</radio-button>
<radio-button tabindex="-1">Cola</radio-button>
<radio-button tabindex="-1">Ginger Ale</radio-button>
</radio-group>
이 구성요소는 키보드 이벤트 리스너를 사용하여 사용자가 누른 키를 확인합니다. 이 경우 이전에 포커스가 맞춰진 하위 요소의 tabindex
를 -1로 설정하고 포커스를 맞출 하위 요소의 tabindex
를 0으로 설정하고 포커스 메서드를 호출합니다.
<radio-group>
<!-- Assuming the user pressed the down arrow, we'll focus the next available child -->
<radio-button tabindex="-1">Water</radio-button>
<radio-button tabindex="0">Coffee</radio-button> // call .focus() on this element
<radio-button tabindex="-1">Tea</radio-button>
<radio-button tabindex="-1">Cola</radio-button>
<radio-button tabindex="-1">Ginger Ale</radio-button>
</radio-group>
사용자가 마지막 (또는 포커스를 이동하는 방향에 따라 첫 번째) 하위 요소에 도달하면 포커스가 첫 번째 (또는 마지막) 하위 요소로 다시 돌아갑니다.
다음 예시를 사용해 보세요. DevTools에서 요소를 검사하여 tabindex가 한 라디오에서 다음 라디오로 이동하는지 확인합니다.
모달 및 키보드 트랩
복잡한 상황이 발생할 수 있으므로 포커스를 수동으로 관리하지 않는 것이 좋습니다. 예를 들어 포커스를 관리하고 탭 동작을 캡처하려고 하지만 사용자가 완료될 때까지 이를 벗어나지 못하도록 하는 자동 완성 위젯이 있습니다. 이를 키보드 트랩이라고 하며 사용자에게 매우 답답할 수 있습니다.
WCAG의 섹션 2.1.2에서는 키보드 포커스가 특정 페이지 요소에 잠기거나 갇혀서는 안 된다고 명시합니다. 사용자가 키보드만 사용하여 모든 페이지 요소로 이동할 수 있어야 합니다.
이 규칙의 예외는 모달입니다. 하지만 모달을 만들 때는 tabindex
을 사용하지 않는 것이 좋습니다. inert
를 사용하면 사용자가 실수로 요소와 상호작용하지 않도록 할 수 있습니다 (의도적인 키보드 트랩). 기본적으로 비활성인 <dialog>
요소를 사용하여 모달 외부의 클릭과 탭을 차단하면서 사용자를 위한 모달을 만듭니다. 이를 통해 사용자는 필수 선택사항에 집중할 수 있습니다.