ReorderList
키보드와 포인터 드래그로 항목 순서를 바꾸는 제어형 리스트 — Alt/Ctrl+화살표, aria-live 공지, lifted drag, live gap, FLIP 스프링 정착을 제공합니다.
마지막 업데이트 2026-07-01
한눈에#
작업 우선순위, 즐겨찾기, 규칙 순서처럼 순서 자체가 데이터인 리스트에 쓰는 재정렬 컴포넌트입니다. 상태는 소비자가 소유하고, onReorder가 다음 items 배열과 이동 정보를 돌려줍니다.
Alt 또는 Ctrl과 위/아래 화살표로 순서를 변경합니다.
- 긴급 이슈 분류
- 디자인 검수 반영
- 릴리즈 노트 정리
- keyboard-first
- aria-live
- live gap
- FLIP spring
핸들에 포커스한 뒤 Alt/Ctrl + ↑/↓로 이동하거나, 핸들을 드래그해 순서를 바꿉니다
사용 시점#
권장 — 이렇게 쓰세요
지양 — 이러지 마세요
Alt 또는 Ctrl과 위/아래 화살표로 순서를 변경합니다.
- 긴급 이슈 분류
- 디자인 검수 반영
- 릴리즈 노트 정리
쓴다 — 항목의 순서가 저장되는 설정·규칙·작업 목록
대신 Table — 단순 데이터 표시는 행 재정렬보다 읽기/비교가 중심일 때
대신 DataGrid — 컬럼 정렬·선택·편집이 중심인 고밀도 표
조작#
Alt 또는 Ctrl과 위/아래 화살표로 순서를 변경합니다.
- 긴급 이슈 분류
- 디자인 검수 반영
- 릴리즈 노트 정리
핸들은 항목마다 제공되는 아이콘 버튼입니다. 키보드는 Alt 또는 Ctrl + ArrowUp/ArrowDown만 순서 변경으로 처리하므로 일반 화살표 탐색과 충돌하지 않습니다. 포인터 드래그는 같은 onReorder 계약을 사용합니다.
모션#
포인터로 잡은 항목은 raised surface로 살짝 떠오르고, 이동 범위의 형제 항목은 translate3d로 위/아래에 live insertion gap을 엽니다. 긴 목록에서는 포인터가 스크롤 컨테이너 가장자리로 가까워질 때 컨테이너를 조금씩 따라 스크롤하고, 그 스크롤량을 드래그 offset에도 반영해 항목이 포인터에서 미끄러져 보이지 않게 합니다.
순서가 바뀐 뒤 항목은 FLIP(First · Last · Invert · Play) 방식으로 이전 위치에서 새 위치로 정착합니다. 이전/이후 좌표 차이를 translate3d로 되감은 뒤 transform을 해제하므로 레이아웃 속성을 애니메이션하지 않습니다. 정착은 모션 SSOT의 spring.spatial.fast를 쓰고, prefers-reduced-motion: reduce에서는 transition을 끄고 새 순서를 즉시 표시합니다.
| 속성 | 토큰/값 |
|---|---|
| 드래그 lift | --wds-shadow-lg + scale(1.015) |
| live gap | 형제 항목 translate3d displacement |
| 위치 정착 | --wds-spring-spatial-fast-duration + --wds-spring-spatial-fast |
| 상태 색 | --wds-spring-effect-fast-duration + --wds-spring-effect-fast |
| reduced motion | transition 없음 |
Props#
| Prop | 타입 | 기본값 | 설명 |
|---|---|---|---|
items | readonly T[] | — | Ordered item data. The caller owns state and applies onReorder results. |
getId | (item: T, index: number) => string | — | Stable item id. Index keys are unsafe because this component reorders. |
renderItem | (item: T, index: number) => ReactNode | — | Render item content. The drag handle is provided by ReorderList. |
label | string | — | Accessible list name. |
onReorder | (change: ReorderListChange<T>) => void | — | Called with the next ordered items after keyboard or pointer reorder. |
getItemLabel | (item: T, index: number) => string | — | Accessible item label for move announcements. Defaults to the item id. |
disabled | boolean | false | Disable every handle. |
itemDisabled | (item: T, index: number) => boolean | — | Disable individual item handles. Disabled items stay rendered but cannot be dragged. |
ref | Ref<HTMLDivElement> | — | Root <div> ref (React 19 ref-as-prop). |
접근성#
- 리스트에는
label로 접근성 이름을 제공합니다 - 각 핸들은 항목 라벨 기반의
aria-label을 갖습니다 - 순서 변경 후
role="status"+aria-live="polite"로 새 위치를 공지합니다 - 드래그만으로만 가능한 동작은 없습니다. 키보드 재정렬이 기본 계약입니다
- 비활성 항목은 핸들을 disabled 처리해 순서 변경 대상에서 제외합니다