로빙 탭인덱스

Roving Tabindex

툴바나 리스트처럼 여러 항목이 모인 위젯에서, Tab은 위젯 전체를 한 번만 들르고 화살표 키가 그 안의 이동을 맡게 하는 패턴.

다른 이름: roving tabindex pattern
···
html
<div class="stage">
  <div class="toolbar">
    <div class="item i0"><div class="ic"></div><div class="ti">0</div></div>
    <div class="item i1"><div class="ic"></div><div class="ti">-1</div></div>
    <div class="item i2"><div class="ic"></div><div class="ti">-1</div></div>
    <div class="item i3"><div class="ic"></div><div class="ti">-1</div></div>
  </div>
  <div class="hint" id="hint">⇥ Tab enters once</div>
</div>
css
.stage{width:92%;height:80%;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12%}
.toolbar{display:flex;gap:6%;padding:5% 6%;border-radius:12px;border:1px solid var(--line);background:var(--surface)}
.item{display:flex;flex-direction:column;align-items:center;gap:8px}
.ic{width:11vmin;max-width:44px;aspect-ratio:1;border-radius:9px;border:1px solid var(--line);background:var(--bg)}
.item.active .ic{box-shadow:0 0 0 3px var(--accent)}
.ti{font:700 11px/1 ui-monospace,monospace;color:var(--muted)}
.item.active .ti{color:var(--accent);font-weight:800}
.hint{font:700 12px/1 ui-monospace,monospace;color:var(--muted);min-height:14px}
js
const items = [0, 1, 2, 3].map(function (i) { return document.querySelector('.i' + i); });
const hint = document.getElementById('hint');
let active = 0;
function render() {
  items.forEach(function (el, i) {
    el.classList.toggle('active', i === active);
    el.querySelector('.ti').textContent = i === active ? '0' : '-1';
  });
}
render();
let step = 0;
function tick() {
  if (step === 0) {
    hint.textContent = '⇥ Tab enters once';
  } else {
    active = (active + 1) % items.length;
    render();
    hint.textContent = '→ moves the roving index';
  }
  step = (step + 1) % items.length;
}
setInterval(tick, 1000);

메뉴바에 항목이 8개 있다고 각각 Tab 정지점이 되면, 사용자는 메뉴 하나를 지나가는 데만 Tab을 8번 눌러야 합니다. 로빙 탭인덱스 패턴은 위젯 안에서 **딱 하나의 항목만** `tabindex="0"`을 갖고 나머지는 전부 `tabindex="-1"`로 둬서, Tab으로는 위젯 전체가 정지점 하나로만 잡히게 합니다.

위젯에 포커스가 들어온 뒤에는 화살표 키가 tabindex 값을 옮겨 다니며 이동을 처리합니다 — 이전 항목은 -1로, 새 항목은 0으로 바뀌고 그 항목에 실제로 포커스를 줍니다. 툴바·탭·리스트박스·메뉴 같은 ARIA 복합 위젯(composite widget) 패턴의 핵심 메커니즘입니다.

데모는 툴바 4개 항목의 tabindex 값이 화살표 키를 누를 때마다 0과 -1 사이를 옮겨 다니는 과정을 배지로 보여줍니다.

언제 쓰나

직접 만든 툴바·탭·리스트박스에서 각 항목을 전부 Tab 정지점으로 만들지 마세요. 항목이 3개 이상이면 로빙 탭인덱스나 aria-activedescendant로 바꾸는 걸 고려하세요.