시맨틱 HTML 요소의 DOM 위치에 의해 제공되는 기본 탭 순서는 편리하지만 탭 순서를 수정해야 할 수도 있습니다. HTML에서 요소를 이동하는 것이 이상적이지만 현실적이지 않을 수 있습니다. 이 경우 tabindex
HTML 속성을 사용하여 요소의 탭 위치를 명시적으로 설정할 수 있습니다.
tabindex
은 모든 요소에 적용할 수 있지만 모든 요소에 반드시 유용한 것은 아니며 다양한 정수 값 범위를 사용합니다. tabindex
를 사용하면 포커스 가능 페이지 요소의 명시적인 순서를 지정하고 포커스 불가능한 요소를 탭 순서에 삽입하며 탭 순서에서 요소를 삭제할 수 있습니다. 예를 들면 다음과 같습니다.
tabindex="0"
: 일반적인 탭 순서에 요소를 삽입합니다. Tab 키를 눌러 요소에 포커스를 둘 수 있고 focus()
메서드를 호출하여 요소에 포커스를 둘 수 있습니다.
tabindex="-1"
: 일반적인 탭 순서에서 요소를 삭제하지만 focus()
메서드를 호출하여 요소에 계속 포커스를 둘 수 있습니다.
tabindex="5"
: 0
보다 큰 tabindex를 지정하면 해당 요소를 자연스러운 탭 순서 앞으로 가져옵니다. tabindex가 0
보다 큰 요소가 여러 개 있다면 탭 순서는 0보다 큰 가장 낮은 값부터 시작하여 위로 올라갑니다. 0
보다 큰 tabindex를 사용하는 것은 피해야 할 패턴으로 간주됩니다.
헤더, 이미지 또는 문서 제목과 같은 비입력 요소의 경우에 특히 그렇습니다. 가능하면 DOM 시퀀스에서 논리적인 탭 순서를 제공하도록 소스 코드를 구성하는 것이 가장 좋습니다. tabindex
를 사용하는 경우 버튼, 탭, 드롭다운, 텍스트 필드와 같은 맞춤 대화형 컨트롤(사용자가 입력을 제공할 것으로 예상되는 요소)으로 제한합니다.
대화형 콘텐츠에만 tabindex
를 추가하세요. 콘텐츠가 키 이미지와 같이 중요한 경우에도 스크린 리더 사용자는 포커스를 추가하지 않고도 해당 콘텐츠를 이해할 수 있습니다.
페이지 수준에서 포커스 관리
원활한 사용자 환경을 위해 tabindex
가 필요한 경우도 있습니다. 예를 들어
모든 콘텐츠가 동시에 표시되지는 않는 여러 콘텐츠 섹션이 포함된
강력한 단일 페이지를 빌드하는 경우입니다. 즉, 탐색 링크가 페이지를 새로고침하지 않고도 표시되는 콘텐츠를 변경할 수 있습니다.
이 경우 선택된 콘텐츠 영역을 식별하고 tabindex
의 -1
을 부여하고 focus
메서드를 호출합니다. 이렇게 하면 콘텐츠가 자연스러운 탭 순서로 표시되지 않습니다. 포커스 관리라고 하는 이 기술은 사용자가 인식하는 컨텍스트를 사이트의 시각적 콘텐츠와 동기화된 상태로 유지합니다.
구성요소의 포커스 관리
경우에 따라 맞춤 구성요소와 같이 컨트롤 수준에서 포커스를 관리해야 합니다.
예를 들어 select
요소는 기본 포커스를 받을 수 있지만 일단 포커스를 받으면 화살표 키를 사용하여 선택 가능한 추가 옵션을 노출할 수 있습니다.
맞춤 select
요소를 빌드하는 경우 키보드 사용자가 계속해서 컨트롤과 상호작용할 수 있도록 이 동작을 복제하는 것이 중요합니다.
어떤 키보드 동작을 구현할지 알기 어려울 수 있습니다. 액세스 가능한 리치 인터넷 애플리케이션 (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
를 -1로 설정하면 이동 tabindex가 작동합니다.
<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>
요소를 사용하여 모달 외부의 클릭 및 탭을 차단하면서 사용자를 위한 모달을 만듭니다. 이렇게 하면 사용자가 필요한 선택에 집중할 수 있습니다.