Kanban boards, sortable lists, file drop zones -- drag and drop is everywhere in modern apps. Playwright gives you two approaches: the simple dragTo() method and the manual mouse-step approach for complex cases.
import { test, expect } from '@playwright/test';
test('drag item to drop zone', async ({ page }) => {
await page.goto('/topics/drag-drop');
const source = page.locator('#draggable');
const target = page.locator('#droppable');
// One line. Done.
await source.dragTo(target);
await expect(target).toContainText('Dropped!');
});
test('reorder items in a sortable list', async ({ page }) => {
await page.goto('/topics/drag-drop');
const firstItem = page.locator('.sortable-item').nth(0);
const thirdItem = page.locator('.sortable-item').nth(2);
// Drag first item to third position
await firstItem.dragTo(thirdItem);
// Verify new order
const items = page.locator('.sortable-item');
await expect(items.nth(0)).toContainText('Item B');
await expect(items.nth(2)).toContainText('Item A');
});Some drag-and-drop libraries (like react-dnd or SortableJS) do not respond to dragTo() because they listen for specific mouse event sequences. In those cases, you need to simulate the exact mouse movements manually.
import { test, expect } from '@playwright/test';
test('manual drag and drop for complex UI', async ({ page }) => {
await page.goto('/topics/drag-drop');
const source = page.locator('#kanban-card');
const target = page.locator('#done-column');
// Get bounding boxes
const sourceBox = await source.boundingBox();
const targetBox = await target.boundingBox();
if (!sourceBox || !targetBox) throw new Error('Element not found');
// Step 1: Move to center of source
await page.mouse.move(
sourceBox.x + sourceBox.width / 2,
sourceBox.y + sourceBox.height / 2
);
// Step 2: Press and hold
await page.mouse.down();
// Step 3: Move to center of target (with intermediate steps)
await page.mouse.move(
targetBox.x + targetBox.width / 2,
targetBox.y + targetBox.height / 2,
{ steps: 10 } // Smooth movement in 10 steps
);
// Step 4: Release
await page.mouse.up();
await expect(target).toContainText('Kanban Card');
});Get bounding boxes of source and target elements
Move mouse to center of source element
Press mouse button down (mouse.down)
Move mouse to center of target with intermediate steps
Release mouse button (mouse.up)
Verify the element moved to the target
The { steps: 10 } option in mouse.move() is important. Some drag libraries need intermediate mousemove events to register the drag. Without steps, the mouse teleports from source to target and the library may not detect the drag motion.
Q: How do you automate drag and drop in Playwright?
A: I start with locator.dragTo(target) -- it works for most standard implementations. If dragTo() does not trigger the drop (common with libraries like react-dnd), I fall back to manual mouse steps: mouse.move() to the source center, mouse.down(), mouse.move() to the target with steps for smooth motion, then mouse.up(). The steps parameter is critical because some libraries need intermediate mousemove events to register the drag. I always verify the element actually moved to the target after the drop.
Key Point: Try dragTo() first. If it does not work, use manual mouse steps: move to source, mouse.down(), move to target with steps, mouse.up(). The steps parameter matters.