dnd kit Mobile: Touch-Drag, ohne das Scrollen zu blockieren

Du hast mit dnd kit eine sortierbare Liste oder ein Kanban-Board gebaut. Mit der Maus läuft alles, auf dem Smartphone klappt nichts mehr: Die Seite scrollt, während die Karte stehen bleibt, oder die Karte schnappt sich jedes Wischen, und die Liste scrollt nie. Dieses Tutorial bringt den dnd kit Mobile-Drag Schritt für Schritt in Ordnung: welche Sensoren du registrierst, der Kompromiss zwischen Aktivierungs-Delay und Scrollen, wohin touch-action gehört, warum iOS Safari Drags abbricht und welche Wege per Tastatur und Tap Drag and Drop barrierefrei machen. Das Sensor-Setup ist das aus dem Kanban von Wingo UI, auf dem die Deal Pipeline aufbaut; die List zeigt die Variante mit Drag-Handle.
Stand Oktober 2026 ist die neueste Version von @dnd-kit/core noch 6.3.1 vom Dezember 2024, und die Legacy-Doku (opens in a new tab) empfiehlt die neue Version von dnd kit (@dnd-kit/react für React), die bei 0.5.0 steht, also vor 1.0. Dieser Artikel zielt auf @dnd-kit/core 6.3.1 und @dnd-kit/sortable 10.0.0.
Warum funktioniert dnd kit auf dem Smartphone nicht?
Weil DndContext standardmäßig den PointerSensor und den KeyboardSensor nutzt, und Pointer Events ein Scrollen nicht stoppen können. Bewegt sich ein Finger auf einem Element, das Panning erlaubt, beginnt der Browser zu scrollen und feuert pointercancel. Das beendet den Drag, und preventDefault() in pointermove ändert daran nichts. Die Doku zum Pointer-Sensor von dnd kit (opens in a new tab) sagt es klar: touch-action: none; ist dort der einzige verlässliche Weg, das Scrollen bei Pointer Events zu verhindern.
Damit bleiben zwei Werkzeuge, beide mit einem Haken:
touch-action: noneauf dem Draggable. Der Drag funktioniert, aber ein Wischen, das auf diesem Element beginnt, kann die Seite nie scrollen. Für einen kleinen Griff in Ordnung, schlecht für eine Liste aus Zeilen in voller Breite: Steht jede Zeile aufnone, scrollt kein Wischen auf der Liste. Die Doku schlägtnonedeshalb nur für einen Drag-Handle vor.- Der TouchSensor. Touch Events lassen sich in
touchmoveabbrechen, also kann ein Drag auf einen Long Press warten und trotzdem ein Wischen scrollen lassen. Dieselbe Doku-Seite empfiehlt die Mouse- und Touch-Sensoren immer dann, wennnonenicht zu deinem Layout passt.
Das Problem ist alt: Issue #435 (opens in a new tab) vom August 2021 beschreibt, dass Drag mit dem PointerSensor auf Touch-Geräten schlecht funktioniert. Wenn die Zeilen selbst scrollen müssen, braucht React Drag and Drop auf Touch-Geräten den TouchSensor, neben einem Sensor für die Maus.
Welche dnd kit Sensoren funktionieren auf einem Touchscreen?
Drei: ein Pointer-Sensor, der Finger ignoriert, der dnd kit Touch Sensor mit Delay und der Keyboard-Sensor. Die Falle ist, den Standard-PointerSensor neben dem TouchSensor zu registrieren. Ein Touch feuert pointerdown vor touchstart, und DndContext ignoriert den Activator eines Sensors, solange ein anderer Sensor noch aussteht; der Check im Quelltext von 6.3.1 trägt einen Kommentar, dass gerade schon ein anderer Sensor instanziiert wird. Der PointerSensor nimmt also jeden Finger, und das Delay des TouchSensor läuft nie.
Wir haben es mit @dnd-kit/core 6.3.1 in headless Chromium mit emuliertem Touch getestet: ein Draggable auf einer Seite, die höher als der Bildschirm ist, 8px Distanz am Pointer-Sensor, 250ms und 8px am TouchSensor, und ein Finger, der sich 60px bewegt, entweder sofort oder nach 400ms Halten.
Ein verbreiteter Workaround wählt einen Sensor nach Gerätetyp. Das scheitert auf Laptops mit Touchscreen, wo dieselbe Person Trackpad und Bildschirm nutzt. Die letzte Zeile ist die sauberere Lösung: eine Unterklasse von PointerSensor, deren Activator Touch-Pointer überspringt. So nehmen Maus und Stift den Pointer-Weg und Finger den Touch-Weg. Unser Kanban nutzt dieselben Pointer- und Touch-Sensoren. Speicher das als components/use-drag-sensors.ts; das komplette Beispiel am Ende importiert es:
Die Kombination aus Standard-MouseSensor und TouchSensor aus der Doku funktioniert ebenfalls.
Welches Delay und welche Toleranz sollte der TouchSensor haben?
250ms mit 5 bis 8px Toleranz. Das Delay ist die Zeit, die ein Finger ruhen muss, bevor die Karte sich hebt. Die Toleranz ist die Strecke, die er in dieser Zeit driften darf, bevor dnd kit aufgibt und den Browser scrollen lässt. In diesen beiden Zahlen steckt der ganze Kompromiss zwischen dnd kit mobile Scroll und Drag:
Nimm nie eine Toleranz von null. Laut Doku zum Touch-Sensor (opens in a new tab) bricht mit null jede Bewegung während des Delays den Drag ab, und ein Finger auf Glas bewegt sich immer ein wenig. Issue #1955 (opens in a new tab), im März 2026 gegen die Neufassung eröffnet, meldete Drags, die auf manchen Android-Smartphones nie starteten, vor allem auf Samsung-Geräten; im Juli 2026 fand der Autor des Issues die Ursache in einem tolerance: 0 und behob sie mit 5. Der PointerSensor der Neufassung gibt Touch standardmäßig 250ms Delay mit 5px Toleranz (opens in a new tab); unser Kanban und die Deal Pipeline nutzen 250ms und 8px.
Ein Long Press braucht Feedback genau in dem Moment, in dem er auslöst, sonst lassen Leute zu früh los. Das Kanban ruft in onDragStart navigator.vibrate(10) auf, wenn das Activator-Event ein TouchEvent ist, und hebt die Karte mit einer kleinen Skalierung und 2 Grad Neigung per Spring-Animation an. Auf dem iPhone bewirkt der Tick nichts, denn Safari auf iOS hat keine Vibration API (caniuse (opens in a new tab), geprüft im Oktober 2026; was ein iPhone stattdessen kann, steht im Guide zur Web Vibration API).
Wohin gehört touch-action?
Auf das Element, das die Listener bekommt, mit einem Wert, der davon abhängt, welcher Sensor den Finger übernimmt. Die Doku empfiehlt manipulation für den TouchSensor und none für den PointerSensor. Der Browser liest den Wert, wenn der Touch beginnt: Eine Änderung nach pointerdown oder touchstart wird ignoriert. Schreib ihn also ins CSS, nie in einen Handler für den Drag-Start.
manipulation behält Panning und Pinch-Zoom und schaltet den Zoom per Doppeltipp ab; sobald der Drag aktiv ist, bricht der TouchSensor touchmove selbst ab. Eine Fläche mit Long Press braucht zwei weitere Klassen: select-none, damit der Druck nicht den Text der Karte markiert, und [-webkit-touch-callout:none], damit iOS sein Callout nicht öffnet. dnd kit bricht contextmenu auf dem Window schon selbst ab, solange ein Touch aussteht oder ein Drag läuft.
Die List von Wingo UI geht den Weg mit Griff: ein 32px-Button mit touch-none, dessen Trefferfläche bei groben Pointern auf 44px wächst (warum 44px). Ein Wischen auf der Zeile scrollt also weiter die Seite oder öffnet ihre Swipe-Aktionen.
Warum bricht ein Drag auf dem iPhone ab, wenn die Seite scrollt?
Weil @dnd-kit/core jeden Pointer- oder Touch-Drag bei einem resize des Fensters abbricht, und Safari auf iOS resize feuert, wenn die Toolbar beim Scrollen des Dokuments ein- oder ausklappt. Issue #686 (opens in a new tab) hat das im März 2022 unter iOS 15 eingegrenzt. Geschlossen wurde es im Februar 2026, weil es gegen die alte Version gemeldet war, nicht weil es behoben wurde: Der resize-Listener steckt noch in den Sensoren von 6.3.1, der Abbruch passiert also weiterhin.
Die Lösung liegt im Layout: Halte den Drag in einem eigenen Scroll-Container, damit sich das Dokument nicht bewegt. Gib dem Board oder der Liste eine echte Höhe (h-dvh, oder flex-1 min-h-0 in einem Layout mit voller Höhe; siehe 100vh auf dem Smartphone), overflow-y-auto für eine Liste oder overflow-x-auto für ein Board, und overscroll-contain, damit das Scrollen am Ende nicht auf die Seite übergeht.
Der Container entscheidet auch, was Auto-Scroll bewegt. dnd kit scrollt die scrollbaren Vorfahren des Elements, also Elemente mit overflow auf auto oder scroll, plus das Dokument, sobald der Pointer weniger als 20% von ihrem Rand entfernt ist. Ein Wrapper mit overflow: hidden zählt nicht. Ein Board, das so abgeschnitten wird, kann also nicht zu seinen versteckten Spalten scrollen; stattdessen scrollt die Seite, falls sie kann. Nutzt ein Board auf dem Smartphone Scroll Snap, pausier es während des Drags: Das Kanban-Board ist snap-x snap-mandatory mit data-dragging:snap-none, damit der Auto-Scroll zur nächsten Spalte gleiten kann.
Probier es in Smartphone-Breite aus (oder im Device Mode): Das Kanban zeigt jeweils eine Spalte, die nächste lugt hervor, ein Wischen scrollt, und 250ms Drücken hebt eine Karte an, die du an den Rand tragen kannst, um die nächste Spalte zu erreichen.
$ npx wingo-ui@latest add kanbanWie machst du Drag and Drop barrierefrei?
Mit zwei getrennten Wegen, und einen davon liefert dnd kit mit. Der KeyboardSensor deckt Tastaturnutzer ab: Standardmäßig hebt Leertaste oder Enter an, die Pfeiltasten bewegen, Leertaste, Enter oder Tab legen ab und Escape bricht ab, während DndContext Anleitungen und Live-Ansagen an Screenreader gibt. Schreib eigene announcements, denn die Standardtexte lesen rohe IDs vor (Picked up draggable item d02.). Das Kanban übergibt keyboardCodes: { start: ["Space"], cancel: ["Escape"], end: ["Space", "Enter"] }, weil Enter eine Karte öffnet, und sein eigener coordinateGetter schickt Links und Rechts zur nächstgelegenen Karte in der nächsten Spalte, die sie annimmt.
Der zweite Weg ist für Menschen, die tippen, aber nicht ziehen können, wegen eines Tremors, eines Trackballs oder einer Kopfmaus. Das WCAG-2.2-Erfolgskriterium 2.5.7 Dragging Movements (opens in a new tab) (Stufe AA) verlangt, dass sich jede Ziehbewegung auch mit einem einzelnen Pointer ohne Ziehen erledigen lässt, und die Erläuterung des W3C stellt klar, dass eine Tastaturalternative allein dafür nicht reicht. Eines ihrer Beispiele ist genau das Muster, das eine Liste braucht: Nach einem Tap auf ein Element verschieben Bedienelemente daneben das Element nach oben oder unten. Bei einem Board übernimmt das ein Menü, das die Zielspalte nennt. Das Kanban setzt „Move to“ an die erste Stelle im ⋯-Menü jeder Karte, das sich auf Smartphones als Bottom Sheet öffnet.
Wie baust du eine sortierbare Liste, die auf Smartphones funktioniert?
Kombinier alles bisher Gezeigte in einer Komponente: den Hook useDragSensors, Zeilen mit Long Press, eine Liste mit eigenem Scroller, benannte Ansagen und Buttons nach oben und unten für den Tap-Weg. Sie übergibt außerdem id={useId()} an DndContext. Ohne das nummeriert dnd kit seine aria-describedby-IDs mit einem Zähler auf Modulebene, Server und Browser können unterschiedlich zählen, und React meldet in Next.js einen Hydration Mismatch.
Installier die Pakete mit npm i @dnd-kit/core @dnd-kit/sortable @dnd-kit/utilities lucide-react und den kostenlosen Button mit npx wingo-ui@latest add button. Speicher das dann als components/sortable-tasks.tsx, neben use-drag-sensors.ts:
Eine Server-Seite wie app/tasks/page.tsx kann sie mit einfachen Daten rendern:
Teste dann auf einem echten Smartphone: Der Device Mode zeigt weder die Toolbar von Safari noch die Drift eines echten Fingers oder den Long Press des Systems. Probier außerdem jeden Weg mit eingeschaltetem Screenreader aus.
Wenn du diesen Code für eine einfache Liste lieber nicht selbst pflegen willst: Die List hat sortierbare Zeilen eingebaut. Schalte sortable ein, dann zieh eine Zeile an ihrem Griff, oder geh per Tab zu einem Griff und nutz Leertaste und Pfeiltasten; Alt mit Pfeil nach oben oder unten verschiebt eine fokussierte Zeile um eine Stelle. Einen Tap-Weg zum Umsortieren hat sie nicht. Für 2.5.7 ergänzt du deshalb Einträge „Move up“ und „Move down“ im actions-Menü jeder Zeile (ihr ⋯-Button ist auf Touch-Geräten immer sichtbar) und sortierst deine items in deren Handlern um.
$ npx wingo-ui@latest add listGibt es ein React Kanban Board, das schon auf Smartphones funktioniert?
Ja: Das Kanban von Wingo UI liefert das Setup für Touch, Maus und Tastatur aus diesem Artikel, das Menü „Move to“ und das Smartphone-Layout mit. Der Guide zum React Kanban Board behandelt seine WIP-Limits, den kontrollierten Wert und das einspaltige Layout auf dem Smartphone. npx wingo-ui@latest add kanban kopiert es samt allem, was es importiert, in dein Projekt und installiert seine npm-Pakete. Kanban, List und Deal Pipeline sind Pro-Komponenten (Preise). Für die anderen Gesten auf dem Smartphone, etwa Swipe-Aktionen und Ziehen zum Schließen, lies den Guide zu Mobile-first React-Komponenten. Der Guide zu React-Formularkomponenten wendet dieselben Regeln für Touch, Tastatur und Screenreader auf jedes Formularelement an, und weitere Tutorials wie dieses findest du in der Kategorie Komponenten-Guides.
Häufige Fragen
Warum funktioniert dnd kit auf dem Smartphone nicht?
DndContext nutzt standardmäßig den PointerSensor, und Pointer Events können den Browser nicht am Scrollen hindern. Ein Touch-Drag wird also abgebrochen, sobald die Seite anfängt zu scrollen. Setz entweder touch-action: none auf einen Drag-Handle, oder lass einen TouchSensor mit 250ms Delay den Finger übernehmen, neben einem Pointer-Sensor, der Touch überspringt: Dann hebt ein Long Press das Element an und ein Wischen scrollt weiter.
Kann ich PointerSensor und TouchSensor in dnd kit zusammen nutzen?
Nicht den Standard-PointerSensor. Ein Touch feuert pointerdown vor touchstart, also schnappt sich der PointerSensor den Finger, und das Delay des TouchSensor läuft nie. Leite eine Klasse von PointerSensor ab, deren Activator, pointerType touch überspringt, oder kombinier MouseSensor mit TouchSensor.
Welches Delay und welche Toleranz sollte der TouchSensor von dnd kit haben?
Starte mit 250ms Delay und 5 bis 8px Toleranz; die Neufassung von dnd kit nutzt 250ms und 5px als Standard für Touch. Setz die Toleranz nie auf 0, denn laut Doku bricht dann jede Bewegung während des Delays den Drag ab, und ein ruhender Finger driftet immer ein wenig.
Warum bricht dnd kit meinen Drag auf dem iPhone ab?
@dnd-kit/core bricht Pointer- und Touch-Drags bei einem Resize des Fensters ab, und Safari auf iOS feuert resize, wenn die Toolbar beim Scrollen ein- oder ausklappt. Halte den Drag in einem eigenen Scroll-Container, damit das Dokument während eines Drags nie scrollt.
Reicht Drag and Drop per Tastatur für Barrierefreiheit?
Es deckt Tastaturnutzer ab, aber nicht das WCAG-2.2-Erfolgskriterium 2.5.7 Dragging Movements, das einen Weg verlangt, dasselbe mit einzelnen Taps oder Klicks zu erledigen. Ergänze neben dem Drag ein Menü „Move to“ oder Buttons nach oben und unten.
Sollte ich für Touch-Drag auf @dnd-kit/react umsteigen?
Nicht nur wegen Touch. Die Legacy-Doku verweist auf die neue Version, und ihr PointerSensor gibt Touch standardmäßig 250ms Delay mit 5px Toleranz, aber Stand Oktober 2026 steht @dnd-kit/react bei 0.5.0, vor 1.0, mit einer anderen API. Auf @dnd-kit/core 6.3.1 behebt das Sensor-Setup aus diesem Artikel den Touch-Drag.
- dnd kit
- Drag and Drop
- Mobile UI
- Barrierefreiheit
- React


