---
title: "HTML5 드래그앤드롭에서 멀티선택 이동 처리, 페이로드가 아니라 드롭 시점에 해석하라"
description: "여러 항목을 선택해도 드래그한 1개만 이동되는 버그를 고쳤습니다. 선택 배열을 페이로드에 담는 대신 드롭 시점에 선택 상태와 대조해 bulk, single, blocked 로 나누는 방법입니다."
date: 2026-10-28
updated: 2026-10-28T03:39:39.942Z
tags: [react, html5-dnd, frontend, ux]
canonical: https://blog.wooncloud.com/posts/html5-dnd-multi-select-resolve-at-drop
---

파일 관리 화면에서 여러 항목을 선택한 뒤 드래그 앤 드롭으로 폴더에 옮기는 기능을 만지다가 버그를 하나 만났습니다. 여러 개를 선택해도 드래그한 1개만 이동되는 겁니다.

![선택 상태를 드래그 시작 시점에 페이로드로 굳히면 어긋나지만, 드롭 시점에 선택과 대조해 해석하면 맞게 옮겨진다.](/images/posts/html5-dnd-multi-select-resolve-at-drop/32a40d07-a544-47a5-86da-e7037ead9a91.webp)

## 선택 배열을 페이로드에 담으면 안 될까

HTML5 DnD 의 `dataTransfer.setData()` 는 dragstart 시점에 호출되고, 드래그를 시작한 그 항목의 정보만 담기 쉽습니다. 그래서 "선택된 전체"를 옮기려면 선택 배열 전체를 페이로드에 직렬화하고 싶어집니다. 저도 처음엔 그랬습니다.

하지만 이러면 문제가 생깁니다. dragstart 마다 선택 상태 스냅샷이 페이로드에 박제되니, 드래그 도중 선택이 바뀌면 어긋납니다. 선택은 그대로 둔 채 선택 안 된 다른 항목 1개만 옮기는 경우도 페이로드만으로는 구분할 수 없습니다. 페이로드 크기와 직렬화 비용도 늘고요.

## 드롭 시점에 해석하기

페이로드에는 드래그한 항목 1개만 담고, **드롭 시점에 선택 상태와 대조해서 해석합니다.** Google Drive 와 같은 규칙입니다.

- 드래그한 항목이 선택에 포함돼 있고 선택이 2건 이상이면 선택 전체를 옮깁니다(bulk).
- 드래그한 항목이 선택에 없거나 선택이 1건이면 그 항목만 옮깁니다(single).
- 이동 대상이 선택된 폴더 자기 자신이면 막습니다(blocked).

![드롭 시점에 대상 폴더가 선택된 폴더면 차단하고, 드래그한 항목이 선택에 있고 선택이 2건 이상이면 전체를 옮기며, 그 외에는 드래그한 항목만 옮긴다.](/images/posts/html5-dnd-multi-select-resolve-at-drop/abe422db-b353-4a45-bcf4-67267aa4962e.svg)

이 결정을 순수함수로 분리하면 단위 테스트가 쉬워집니다.

```js
// 드롭 시점에 호출한다. payload 는 dragstart 에 담긴 단일 항목
function resolveDragMove(payload, target, selection) {
  if (target.kind !== 'folder-into') return { mode: 'single' };
  if (selection.folders.has(target.folderId)) return { mode: 'blocked' };

  const selected =
    payload.kind === 'file'
      ? selection.files.has(payload.id)
      : selection.folders.has(payload.id);
  const total = selection.files.size + selection.folders.size;

  return selected && total > 1
    ? { mode: 'bulk', folderId: target.folderId }
    : { mode: 'single' };
}
```

드롭 핸들러에서 `mode === 'bulk'` 이면 기존 벌크 이동 로직(병렬 요청과 낙관적 업데이트)을 재사용하면 됩니다. 멀티선택 툴바의 "이동" 버튼용 벌크 로직이 이미 있다면 새 API 없이 그대로 연결됩니다.

드래그 페이로드를 똑똑하게 만들려다 오히려 꼬였는데, 판단을 드롭 쪽으로 미루니 코드가 훨씬 단순해졌네요.

참고

- [MDN, DataTransfer](https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer)
- [MDN, HTML Drag and Drop API](https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API)
