ドロップが落ちない — 15分で3回直して、原因は3回目だった

自作の音楽生成ツール(mini-music-app)に、保管庫の曲を「参考音源」の欄へドラッグして渡す機能を付けました。 ところが、落としても反応しません。2026-11-10の夕方、この件で3回直しました。
この記事は、3回の直しを、実ブラウザで1つずつ再現して振り返る記録です。 先に結論を書きます。
- 落ちない原因は、ドラッグ元の
effectAllowedとドロップ先のdropEffectの組み合わせでした。直したのは3回目です - 1回目の直しは、別の穴(落とし先の範囲)を塞いでいました
- 2回目の直しは、再現では影響がありませんでした
15分で3回直した
コミットの時刻は、17:13、17:22、17:29です。1回目から3回目まで、約15分でした。
再現する: 必要な部分だけの1ページで、本物のドラッグをする
アプリは音楽生成の画面(Gradio)の上に作ってあり、そのまま調べると要素が多すぎます。 そこで、次の3つだけを置いた1ページを作りました。
- ドラッグ元の行
- ドロップ先の欄(自前)
- アップロード欄の代役(自前とは別に、
dropとdragoverの処理を持つ)
動かすのは、PlaywrightのChromium(151.0.7922.34)です。
page.mouse で、押す、動かす、離す、の本物のマウス操作をして、各イベントが何回届いたかを数えます。
16通りの条件を試しました。同じ条件を複数回動かした分は、結果が毎回同じでした(最後に足した3通りだけ、1回です)。
原因: dragoverは来るのに、dropだけ来ない
表の1行目(A)が、修正前の組み合わせです。
ドラッグ元は、effectAllowed = "move"(動かすことだけを許す)と宣言していました。
ドロップ先は、dropEffect = "copy"(コピーとして受ける)と答えていました。
この組み合わせだと、ブラウザは drop を発火させません。
怖いのは、dragover は毎回来ることです。
このアプリは、dragover の中で枠を強調する作りでした。
強調の処理は走るので、見た目は正しく動いているように見えます。落とせないのに、落とせる見た目です。
(枠の強調はコードから読んだことで、当時の画面は見ていません。)
直し方は2つ、再現で確かめました。
- ドラッグ元を
copyMoveにする(B)。今回選んだ直し方です - ドロップ先で
dropEffectを設定しない。effectAllowed = "move"のままでも、dropが来て、dropEffectはmoveになりました
2回目の直しは、再現では影響が無かった
2回目は、dragover の中の stopPropagation() を外す直しでした。
stopPropagation は、そのイベントを、ほかの処理に届かなくします。
再現では、dragover で stopPropagation を呼んでも、drop は来ました。capture相でもbubble相でも、同じです。
この直しは、drop が来ない原因ではありませんでした。
ただし、副作用はありました。
dragover で止めると、アップロード欄が自分で持つ dragover の処理が、4回から0回になります。drop は、そのまま1回届きます。
実アプリ(Gradio)で、別の影響があったかは確かめていません。 外したこと自体は、害にはなっていないと思います。
1回目の直しは、別の穴を塞いでいた
1回目は、受ける範囲を、自前の欄から、アップロード欄を含む全体へ広げる直しでした。 再現では、確かに意味がありました。
自前の欄だけを受け皿にしていると、アップロード欄に落とした曲は、アップロード欄の既存の処理が受けます。自前の処理には届きません。
範囲を広げて、drop をcapture相で受けて stopPropagation すると、自前の処理だけが動きます。
1回目は、この穴を塞いでいました。 ただ、3回目までの間は、この穴を塞いでも、effectAllowedの食い違いが残っていて、落とせませんでした。
自動テストが通っていた理由
直す間も、自動テストは通っていました。
テストは、偽の document と偽のイベントを作り、登録した関数を直接呼ぶ作りです。
ブラウザの「許可と答えが食い違うと drop を発火させない」という判定は、ここには含まれません。
3回目に足したテストは、effectAllowed が "copyMove" であることの確認です。
drop が来ることの確認ではありません。値を確かめているだけで、挙動は確かめていません。

持ち帰ったこと
- ドロップが落ちないときは、
dragoverが来ているかで安心しない。dropが来ているかを見る effectAllowedとdropEffectは、食い違うとdropが来ない。迷ったら、dropEffectを設定しない- 「直した」の確認は、偽のイベントではなく、本物のドラッグでする。Playwrightなら十数行で書ける
stopPropagationは、止めたい相手の処理を決めてから、その処理が受けるイベントに付ける
まだ確かめていないことが3つあります。
- Chrome以外(Firefox、Safari)の挙動
- 実アプリ(Gradio)の画面で、3回目の直しのあとに落とせること。コミットは入っていて、このあと
dropEffectの周りの変更は無いが、画面での確認は今回していない - タッチ操作
関連する記事です。
- dropが来ない時の確認 — 見る順番、組み合わせの結果、再現の書き方
- ガードが素通りする書き方 — 検査が効いていなかった3つの実例と、壊して確かめる手順
- ハッシュタグ必須と書いても止まらない — 決まりを、止まる仕組みへ移した記録
- 制作物の一覧 — 作っているプロダクトの一覧