스테퍼

Stepper

여러 단계로 이루어진 작업에서 지금 몇 번째 단계인지 번호와 연결선으로 보여주는 표시.

다른 이름: Step indicatorWizard stepsProgress steps
···
html
<ol class="stp">
  <li data-state="done"><span class="num">✓</span>배송지</li>
  <li data-state="current"><span class="num">2</span>결제</li>
  <li data-state="upcoming"><span class="num">3</span>완료</li>
</ol>
css
.stp{list-style:none;display:flex;margin:0;padding:0;width:min(280px,90%)}
.stp li{flex:1;position:relative;display:flex;flex-direction:column;align-items:center;gap:8px;font-size:11px;color:var(--muted)}
.stp li:not(:last-child)::after{content:"";position:absolute;top:13px;left:calc(50% + 20px);width:calc(100% - 40px);height:2px;background:var(--line)}
.stp li[data-state=done]:not(:last-child)::after{background:var(--accent)}
.num{width:26px;height:26px;border-radius:50%;display:grid;place-items:center;font-size:12px;font-weight:700;
  background:var(--line);color:var(--muted);border:2px solid transparent;transition:background .25s,color .25s}
[data-state=current] .num{background:var(--surface);color:var(--accent);border-color:var(--accent)}
[data-state=done] .num{background:var(--accent);color:#fff}
[data-state=current]{color:var(--fg);font-weight:700}
js
const items = [...document.querySelectorAll('.stp li')];
function paint(cur) {
  items.forEach((li, i) => {
    li.dataset.state = i < cur ? 'done' : i === cur ? 'current' : 'upcoming';
    li.querySelector('.num').textContent = i < cur ? '✓' : String(i + 1);
  });
}
let cur = 1;
paint(cur);
setInterval(() => { cur = (cur + 1) % (items.length + 1); paint(cur); }, 1600);

각 단계는 완료/현재/예정 세 가지 상태 중 하나이며, 완료는 체크 아이콘, 현재는 강조 색, 예정은 흐린 색으로 구분합니다. 현재 단계에는 aria-current="step"을 붙여 스크린리더가 "지금 여기"를 알 수 있게 합니다.

프로그레스 바와 다른 점은 이산적이라는 것입니다 — 프로그레스 바는 0~100% 사이 어떤 값이든 연속적으로 표현하지만, 스테퍼는 "배송지 → 결제 → 완료"처럼 이름 붙은 몇 개의 정해진 단계 사이만 오갑니다. 브레드크럼과 다른 점은 방향입니다 — 브레드크럼은 이미 지나온 계층 위치를 보여주고 언제든 상위로 되돌아갈 수 있지만, 스테퍼는 보통 정해진 순서를 따라 앞으로만 진행하는 프로세스를 보여줍니다.

이미 완료한 단계를 다시 눌러 되돌아갈 수 있게 허용할지는 프로세스 성격에 달려 있습니다 — 결제 완료 후에는 보통 이전 단계로 못 돌아갑니다.