tabindex로 DOM 순서 수정

Dave Gash
Dave Gash
Meggin Kearney
Meggin Kearney
Alexandra Klepper
Alexandra Klepper

시맨틱 HTML 요소의 DOM 위치에 의해 제공되는 기본 탭 순서는 편리하지만 탭 순서를 수정해야 할 수도 있습니다. HTML에서 요소를 이동하는 것이 이상적이지만 현실적이지 않을 수 있습니다. 이 경우 tabindex HTML 속성을 사용하여 요소의 탭 위치를 명시적으로 설정할 수 있습니다.

브라우저 지원

  • 1
  • 12
  • 1.5
  • 4점 이하

소스

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> 요소를 사용하여 모달 외부의 클릭 및 탭을 차단하면서 사용자를 위한 모달을 만듭니다. 이렇게 하면 사용자가 필요한 선택에 집중할 수 있습니다.