정의
"이 항목을 집어서 저쪽으로 끌어다 놓는다"를 만들고 싶은데, 그 대상이 서로 다른 목록·영역(React 컴포넌트 경계 너머)에 걸쳐 있을 때 이 API를 쓴다. 브라우저가 직접 드래그를 관리해 주므로 경계를 넘는 이동이 쉬워진다.
HTML5 Drag and Drop은 브라우저가 제공하는 네이티브 드래그 세션(운영체제가 직접 관리하는 진짜 드래그 상태) API다. dragstart → dragover → drop / dragend 이벤트와 DataTransfer(드래그하는 동안 옮길 데이터를 담아 두는 브라우저 내장 상자)로 페이로드(옮기려는 실제 데이터)를 옮기며, 포인터가 OS 드래그 루프에 들어간 뒤에야 동작한다. 프레임워크가 합성한(코드로 흉내 낸) 마우스 이벤트만으로는 세션이 시작되지 않는 경우가 많다.
왜 필요한가
에디터·리스트·파일 업로드에서 “선택 영역을 다른 곳으로 옮긴다”는 UX는 흔하다. React나 인라인 에디터가 한 서브트리만 소유할 때, 프레임워크 내부 DnD로는 경계를 넘지 못한다. HTML5 DnD는 DOM 트리 전체에서 동작하므로, 포커스된 서브트리 밖의 타깃으로 텍스트·노드를 옮기는 채널이 된다.
동작 원리
- 사용자가 선택 영역을 드래그하면
dragstart가 발생하고, 핸들러가dataTransfer에text/plain등 MIME 타입(데이터 형식을 나타내는 이름표, 예: 일반 텍스트/HTML) 페이로드를 넣는다. - 포인터가 이동하는 동안
dragover가 반복된다. 드롭을 허용하려면 타깃에서preventDefault()가 필요하다. drop에서 페이로드를 읽고,caretRangeFromPoint(화면 좌표를 받아 그 지점의 텍스트 커서 위치를 돌려주는 브라우저 함수) 등으로 삽입 위치를 계산한 뒤 도메인 상태에 반영한다.dragend로 세션이 끝난다.img/a는 기본draggable이라 의도치 않은 네이티브 드래그를 유발할 수 있다.
| 항목 | 설명 | 주의점 |
|---|---|---|
dragstart | 세션 시작, 페이로드 설정 | 텍스트 드래그는 selection이 있어야 함 |
dragover | 드롭 허용을 위해 preventDefault() | 안 하면 drop이 발생하지 않음 |
drop | 타깃에서 페이로드 수신 | 삽입 위치 계산이 핵심 |
DataTransfer | MIME별 페이로드 | 브라우저마다 직렬화 차이 |
draggable | 드래그 소스 명시 | 장식 요소는 false로 |
실무 적용
크로스-서브트리 이동이 필요하면 프레임워크 DnD 대신 HTML5 채널을 쓰고, 드롭 결과는 도메인 패치(원자 배치) 로 반영한다. 드래그 시작 시 포커스/에디터 세션을 정리해 소스 오브 트루스 race를 제거한다.
E2E는 OS 드래그 루프를 가정하지 말고, 앱이 듣는 DragEvent를 합성 디스패치해 경로를 검증한다. Playwright 합성 마우스는 OS 루프에 못 들어가 dragstart가 안 나는 경우가 많다.
트레이드오프
- 네이티브 API는 크로스-서브트리·파일 드롭에 강하지만, 브라우저별
DataTransfer·커서·접근성 차이가 있다. - 드래그 중 React 리렌더가 소스/타깃 DOM을 교체하면 세션이 끊긴다. 드래그 중에는 리렌더를 최소화하거나 정적 렌더로 고정해야 한다.
사용하면 안 되는 경우
- 같은 서브트리 안의 단순 재정렬만 필요하고, 포인터 이벤트 + 상태 업데이트로 충분한 경우.
- 터치 전용 UX가 본체인 경우 — HTML5 DnD의 터치 지원은 환경에 따라 제한적이다. Pointer Events(마우스·터치·펜을 하나로 다루는 저수준 입력 이벤트) 기반 대안을 검토한다.
흔한 실수
dragover에서preventDefault()를 빼drop이 영원히 안 온다.- 이미지·링크·핸들 글리프가 텍스트 드래그를 가로챈다 (
draggable={false}/ pseudo-element 미적용). - E2E가 OS 드래그를 가정해 CI에서만 실패한다.
- 드롭 좌표가 contenteditable과 정적 렌더 중 어느 쪽을 가리키는지 구분하지 않는다.
관련 개념
- selection-tostring-and-pseudo-content — 핸들 글리프가 선택/복사에 섞이는 문제와 함께 다루는 경우가 많다.
- focused-guest-editor — guest가 한 블록만 소유할 때 크로스블록 이동 채널로 HTML5 DnD가 자주 선택된다.