QuantityStepper
수량 증감 입력기 — −/값/+ 구성에 min·max·step 클램핑. 진행 단계 Stepper와 역할이 달라 별도 이름을 씁니다(ADR-012 Track C).
마지막 업데이트 2026-06-22
한눈에#
장바구니 수량·인원수처럼 정수를 ±step 단위로 정밀하게 증감하는 −/값/+ 입력기입니다.
- −/값/+ 구성
- min·max·step 클램프
- 2 크기(md·sm)
- 44px 히트 영역
값 칸은 직접 타이핑·화살표 키 증감 모두 가능하고, 한계 도달 시 해당 버튼이 비활성됩니다
진행 단계 표시기 Stepper와 이름이 비슷하지만 역할이 다릅니다 — 이쪽은 수량 입력, Stepper는 진행 단계 표시입니다.
사용 시점#
정수를 ±step 단위로 정밀 증감하면 QuantityStepper — 어림 조절이나 진행 단계 표시는 다른 컴포넌트입니다.
권장 — 이렇게 쓰세요
지양 — 이러지 마세요
쓴다 — 장바구니 수량·인원수처럼 min/max 클램프 + −/+ 버튼이 필요한 정수 증감
대신 Slider — 볼륨·밝기처럼 어림값으로 충분한 연속 조절
대신 Stepper — 진행 단계(스텝 1·2·3) 표시 — 이름만 비슷하고 역할이 다름
플레이그라운드#
컨트롤로 props를 조작하면 미리보기와 코드가 실시간 갱신됩니다.
QuantityStepper를 직접 조작해 보세요
속성·테마·토큰을 바꾸고 React·Flutter 코드를 확인하는 풀스크린 빌더로 엽니다.
플레이그라운드는 넓은 작업 영역이 필요해 웹·태블릿에서 편집할 수 있어요.
해부#
−/값/+ 위에 토큰 실측을 핀으로 얹습니다 — 컨테이너는 입력 어휘(input.*)를 재사용하고, 값이 바뀌면 핀도 함께 움직입니다(드리프트 0).
- height
- 44px
input.height (control.height-md) - button
- 32px
control.height-sm - button hit
- 44px (::after)
- icon
- 20px
icon.size-md - gap
- 4px
space-1 - radius
- 10px
input.radius (control) - border
- 1px
input.border
컨테이너 높이는 input.height(=control.height-md 44px)로 같은 줄의 Input·Select와 자동 정렬됩니다. −/+ 버튼은 시각 32px(control.height-sm)이지만 히트 영역은 ::after로 44px까지 확장됩니다.
변형#
단일 형태입니다 — −/값/+ 구성. 값 칸은 직접 타이핑할 수 있고, 위/아래 화살표
키로도 증감합니다. step으로 증감 단위를, min/max로 범위를 정합니다.
크기#
size로 2단 — md(기본)·sm. 컨테이너 높이만 줄고 버튼 시각·아이콘은 공유하며, 두 크기 모두 −/+ 버튼의 히트 영역을 44px로 유지해 터치 타깃을 보장합니다.
상태#
비제어 컴포넌트입니다 — defaultValue로 시작하고 clamp된 값이 실제로 바뀔 때만
onChange가 발화합니다. 상·하한에서는 해당 버튼이 비활성화되고, 한계 도달 시
중복 발화하지 않습니다. 직접 입력한 값은 [min, max]로 clamp되며, 비숫자 입력은
무시하고 blur 시 마지막 유효값으로 복원합니다.
Props#
| Prop | 타입 | 기본값 | 설명 |
|---|---|---|---|
aria-label | string | — | 값 입력의 접근 이름(예: "수량") — 필수. 루트 group은 컨트롤을 묶기만 한다(중복 announce 회피) |
defaultValue | number | — | 비제어 초기값 — 생략 시 min(있으면) 또는 0 |
onChange | (value: number) => void | — | clamp된 값이 실제로 바뀔 때만 발화 |
min | number | 0 | 하한 — 기본 0 |
max | number | — | 상한 — 기본 없음(무제한) |
step | number | 1 | 증감 단위 — 기본 1 |
disabled | boolean | false | 입력·버튼 모두 비활성 |
size | 'sm' | 'md' | md | 컨트롤 크기 — md(기본) | sm |
ref | Ref<HTMLInputElement> | — | 수량 <input>으로 직결되는 ref — 증감 버튼이 아닌 텍스트 입력 요소 (React 19 ref-as-prop) |
접근성#
- 루트는
role="group"으로 −/값/+ 를 하나의 컨트롤로 묶습니다(이름 중복 announce를 피하기 위해 이름은 값 입력에만 둡니다). - 값 입력은
inputMode="numeric"+aria-label(필수)을 가지며,ArrowUp/ArrowDown으로 증감합니다. −/+버튼은 각각aria-label(“감소”/“증가”)을 가지고, 한계 도달 시disabled됩니다.- 입력은 경계에서 신뢰하지 않습니다 — 숫자만 받고
[min, max]로 clamp, 비숫자는 거부합니다.
토큰#
component 토큰 없이 semantic(+input 어휘)을 직접 소비합니다(신설 기준 §4 미충족).
| 속성 | 토큰 |
|---|---|
| 컨테이너 | input.height · input.bg · input.border(focus input.border-focus) · input.radius |
| 버튼 | control.height-sm 시각 + 44px 히트 · color.text-muted(hover surface-hover → active surface-pressed) · radius.control |
| 값/비활성 | input.fg · color.disabled-fg |
| 포커스 | 컨테이너 color.primary 18% 링 · 버튼 color.focus-ring 2px 아웃라인 |
| 모션 | duration.fast + ease.standard |