Drag and Drop
Implement drag and drop operations for sortable lists, file uploads, and canvas interactions.
Selenium 3 & 4 Medium
Drag and drop is common in modern web applications for reordering lists, moving items between containers, and canvas-based interfaces. Selenium’s Actions API provides several approaches.
Basic Drag and Drop
Simple Drag and Drop
Selenium 3 & 4 Medium
import org.openqa.selenium.interactions.Actions;
WebElement source = driver.findElement(By.id("draggable"));WebElement target = driver.findElement(By.id("droppable"));
// Method 1: dragAndDrop actionActions actions = new Actions(driver);actions.dragAndDrop(source, target).perform();
// Method 2: Explicit stepsactions.clickAndHold(source) .moveToElement(target) .release() .perform();
// Method 3: With offsetactions.dragAndDropBy(source, 100, 50).perform(); // Move by x, y pixelsfrom selenium.webdriver.common.action_chains import ActionChains
source = driver.find_element(By.ID, "draggable")target = driver.find_element(By.ID, "droppable")
# Method 1: drag_and_drop actionactions = ActionChains(driver)actions.drag_and_drop(source, target).perform()
# Method 2: Explicit stepsactions = ActionChains(driver)actions.click_and_hold(source) .move_to_element(target) .release() .perform()
# Method 3: With offsetactions = ActionChains(driver)actions.drag_and_drop_by_offset(source, 100, 50).perform() # Move by x, y// Method 1: Using actionsconst source = await driver.findElement(By.id('draggable'));const target = await driver.findElement(By.id('droppable'));
await driver.actions({ async: true }) .dragAndDrop(source, target) .perform();
// Method 2: Explicit stepsawait driver.actions({ async: true }) .move({ origin: source }) .press() .move({ origin: target }) .release() .perform();
// Method 3: With offsetawait driver.actions({ async: true }) .move({ origin: source }) .press() .move({ x: 100, y: 50 }) .release() .perform();using OpenQA.Selenium.Interactions;
IWebElement source = driver.FindElement(By.Id("draggable"));IWebElement target = driver.FindElement(By.Id("droppable"));
// Method 1: DragAndDrop actionActions actions = new Actions(driver);actions.DragAndDrop(source, target).Perform();
// Method 2: Explicit stepsnew Actions(driver) .ClickAndHold(source) .MoveToElement(target) .Release() .Perform();
// Method 3: With offsetnew Actions(driver) .DragAndDropToOffset(source, 100, 50) .Perform(); // Move by x, y pixelsHandling HTML5 Drag and Drop
HTML5 native drag and drop often doesn’t work with standard Actions. Use JavaScript:
HTML5 Drag and Drop via JavaScript
Selenium 3 & 4 Medium
JavascriptExecutor js = (JavascriptExecutor) driver;
WebElement source = driver.findElement(By.id("drag-source"));WebElement target = driver.findElement(By.id("drop-target"));
// Simulate drag and drop with custom JavaScriptString script = """ function simulateDragDrop(sourceNode, targetNode) { var dataTransfer = new DataTransfer();
var dragStartEvent = new DragEvent('dragstart', { bubbles: true, cancelable: true, dataTransfer: dataTransfer }); sourceNode.dispatchEvent(dragStartEvent);
var dragOverEvent = new DragEvent('dragover', { bubbles: true, cancelable: true, dataTransfer: dataTransfer }); targetNode.dispatchEvent(dragOverEvent);
var dropEvent = new DragEvent('drop', { bubbles: true, cancelable: true, dataTransfer: dataTransfer }); targetNode.dispatchEvent(dropEvent);
var dragEndEvent = new DragEvent('dragend', { bubbles: true, cancelable: true, dataTransfer: dataTransfer }); sourceNode.dispatchEvent(dragEndEvent); } simulateDragDrop(arguments[0], arguments[1]); """;
js.executeScript(script, source, target);source = driver.find_element(By.ID, "drag-source")target = driver.find_element(By.ID, "drop-target")
# Simulate drag and drop with custom JavaScriptscript = """function simulateDragDrop(sourceNode, targetNode) { var dataTransfer = new DataTransfer();
var dragStartEvent = new DragEvent('dragstart', { bubbles: true, cancelable: true, dataTransfer: dataTransfer }); sourceNode.dispatchEvent(dragStartEvent);
var dragOverEvent = new DragEvent('dragover', { bubbles: true, cancelable: true, dataTransfer: dataTransfer }); targetNode.dispatchEvent(dragOverEvent);
var dropEvent = new DragEvent('drop', { bubbles: true, cancelable: true, dataTransfer: dataTransfer }); targetNode.dispatchEvent(dropEvent);
var dragEndEvent = new DragEvent('dragend', { bubbles: true, cancelable: true, dataTransfer: dataTransfer }); sourceNode.dispatchEvent(dragEndEvent);}simulateDragDrop(arguments[0], arguments[1]);"""
driver.execute_script(script, source, target)const source = await driver.findElement(By.id('drag-source'));const target = await driver.findElement(By.id('drop-target'));
// Simulate drag and drop with custom JavaScriptconst script = `function simulateDragDrop(sourceNode, targetNode) { var dataTransfer = new DataTransfer();
var dragStartEvent = new DragEvent('dragstart', { bubbles: true, cancelable: true, dataTransfer: dataTransfer }); sourceNode.dispatchEvent(dragStartEvent);
var dragOverEvent = new DragEvent('dragover', { bubbles: true, cancelable: true, dataTransfer: dataTransfer }); targetNode.dispatchEvent(dragOverEvent);
var dropEvent = new DragEvent('drop', { bubbles: true, cancelable: true, dataTransfer: dataTransfer }); targetNode.dispatchEvent(dropEvent);
var dragEndEvent = new DragEvent('dragend', { bubbles: true, cancelable: true, dataTransfer: dataTransfer }); sourceNode.dispatchEvent(dragEndEvent);}simulateDragDrop(arguments[0], arguments[1]);`;
await driver.executeScript(script, source, target);IJavaScriptExecutor js = (IJavaScriptExecutor)driver;
IWebElement source = driver.FindElement(By.Id("drag-source"));IWebElement target = driver.FindElement(By.Id("drop-target"));
string script = @"function simulateDragDrop(sourceNode, targetNode) { var dataTransfer = new DataTransfer();
var dragStartEvent = new DragEvent('dragstart', { bubbles: true, cancelable: true, dataTransfer: dataTransfer }); sourceNode.dispatchEvent(dragStartEvent);
var dragOverEvent = new DragEvent('dragover', { bubbles: true, cancelable: true, dataTransfer: dataTransfer }); targetNode.dispatchEvent(dragOverEvent);
var dropEvent = new DragEvent('drop', { bubbles: true, cancelable: true, dataTransfer: dataTransfer }); targetNode.dispatchEvent(dropEvent);
var dragEndEvent = new DragEvent('dragend', { bubbles: true, cancelable: true, dataTransfer: dataTransfer }); sourceNode.dispatchEvent(dragEndEvent);}simulateDragDrop(arguments[0], arguments[1]);";
js.ExecuteScript(script, source, target);Sortable Lists
Reorder items in sortable/draggable lists:
Reordering Sortable Lists
Selenium 3 & 4 Medium
// Move item from position 3 to position 1List<WebElement> items = driver.findElements(By.cssSelector(".sortable-list li"));WebElement itemToMove = items.get(2); // 3rd item (0-indexed)WebElement targetPosition = items.get(0); // 1st position
Actions actions = new Actions(driver);actions.clickAndHold(itemToMove) .pause(Duration.ofMillis(500)) // Some libraries need a pause .moveToElement(targetPosition) .pause(Duration.ofMillis(500)) .release() .perform();
// Verify new orderList<WebElement> reorderedItems = driver.findElements(By.cssSelector(".sortable-list li"));for (int i = 0; i < reorderedItems.size(); i++) { System.out.println((i + 1) + ": " + reorderedItems.get(i).getText());}# Move item from position 3 to position 1items = driver.find_elements(By.CSS_SELECTOR, ".sortable-list li")item_to_move = items[2] # 3rd item (0-indexed)target_position = items[0] # 1st position
actions = ActionChains(driver)actions.click_and_hold(item_to_move) .pause(0.5) .move_to_element(target_position) .pause(0.5) .release() .perform()
# Verify new orderreordered_items = driver.find_elements(By.CSS_SELECTOR, ".sortable-list li")for i, item in enumerate(reordered_items): print(f"{i + 1}: {item.text}")// Move item from position 3 to position 1const items = await driver.findElements(By.css('.sortable-list li'));const itemToMove = items[2]; // 3rd item (0-indexed)const targetPosition = items[0]; // 1st position
await driver.actions({ async: true }) .move({ origin: itemToMove }) .press() .pause(500) .move({ origin: targetPosition }) .pause(500) .release() .perform();
// Verify new orderconst reorderedItems = await driver.findElements(By.css('.sortable-list li'));for (let i = 0; i < reorderedItems.length; i++) { console.log(`${i + 1}: ${await reorderedItems[i].getText()}`);}// Move item from position 3 to position 1IList<IWebElement> items = driver.FindElements(By.CssSelector(".sortable-list li"));IWebElement itemToMove = items[2]; // 3rd item (0-indexed)IWebElement targetPosition = items[0]; // 1st position
new Actions(driver) .ClickAndHold(itemToMove) .Pause(TimeSpan.FromMilliseconds(500)) .MoveToElement(targetPosition) .Pause(TimeSpan.FromMilliseconds(500)) .Release() .Perform();
// Verify new orderIList<IWebElement> reorderedItems = driver.FindElements(By.CssSelector(".sortable-list li"));for (int i = 0; i < reorderedItems.Count; i++){ Console.WriteLine($"{i + 1}: {reorderedItems[i].Text}");}Drag Between Containers
Moving items between different drop zones:
Drag Between Containers
Selenium 3 & 4 Medium
// Kanban-style board: move task from "To Do" to "In Progress"WebElement task = driver.findElement( By.xpath("//div[@id='todo']//div[@class='task'][text()='Write tests']"));WebElement inProgressColumn = driver.findElement(By.id("in-progress"));
Actions actions = new Actions(driver);actions.dragAndDrop(task, inProgressColumn).perform();
// Verify task movedWebElement movedTask = driver.findElement( By.xpath("//div[@id='in-progress']//div[@class='task'][text()='Write tests']"));assert movedTask.isDisplayed();# Kanban-style board: move task from "To Do" to "In Progress"task = driver.find_element( By.XPATH, "//div[@id='todo']//div[@class='task'][text()='Write tests']")in_progress_column = driver.find_element(By.ID, "in-progress")
actions = ActionChains(driver)actions.drag_and_drop(task, in_progress_column).perform()
# Verify task movedmoved_task = driver.find_element( By.XPATH, "//div[@id='in-progress']//div[@class='task'][text()='Write tests']")assert moved_task.is_displayed()// Kanban-style board: move task from "To Do" to "In Progress"const task = await driver.findElement( By.xpath("//div[@id='todo']//div[@class='task'][text()='Write tests']"));const inProgressColumn = await driver.findElement(By.id('in-progress'));
await driver.actions({ async: true }) .dragAndDrop(task, inProgressColumn) .perform();
// Verify task movedconst movedTask = await driver.findElement( By.xpath("//div[@id='in-progress']//div[@class='task'][text()='Write tests']"));console.log('Task moved:', await movedTask.isDisplayed());// Kanban-style board: move task from "To Do" to "In Progress"IWebElement task = driver.FindElement( By.XPath("//div[@id='todo']//div[@class='task'][text()='Write tests']"));IWebElement inProgressColumn = driver.FindElement(By.Id("in-progress"));
new Actions(driver).DragAndDrop(task, inProgressColumn).Perform();
// Verify task movedIWebElement movedTask = driver.FindElement( By.XPath("//div[@id='in-progress']//div[@class='task'][text()='Write tests']"));Assert.IsTrue(movedTask.Displayed);Slider Controls
Interact with range sliders:
Slider Manipulation
Selenium 3 & 4 Medium
// Find the sliderWebElement slider = driver.findElement(By.id("price-slider"));
// Get slider dimensionsint width = slider.getSize().getWidth();
// Move slider to 75% positionActions actions = new Actions(driver);actions.clickAndHold(slider) .moveByOffset((int)(width * 0.75) - (width / 2), 0) .release() .perform();
// Alternative: Set value directly via JavaScriptJavascriptExecutor js = (JavascriptExecutor) driver;js.executeScript("arguments[0].value = 75", slider);js.executeScript("arguments[0].dispatchEvent(new Event('change'))", slider);
// Verify valueString value = slider.getAttribute("value");System.out.println("Slider value: " + value);# Find the sliderslider = driver.find_element(By.ID, "price-slider")
# Get slider dimensionswidth = slider.size['width']
# Move slider to 75% positionactions = ActionChains(driver)offset = int(width * 0.75) - (width // 2)actions.click_and_hold(slider) .move_by_offset(offset, 0) .release() .perform()
# Alternative: Set value directly via JavaScriptdriver.execute_script("arguments[0].value = 75", slider)driver.execute_script("arguments[0].dispatchEvent(new Event('change'))", slider)
# Verify valuevalue = slider.get_attribute("value")print(f"Slider value: {value}")// Find the sliderconst slider = await driver.findElement(By.id('price-slider'));
// Get slider dimensionsconst size = await slider.getRect();const width = size.width;
// Move slider to 75% positionconst offset = Math.floor(width * 0.75) - Math.floor(width / 2);await driver.actions({ async: true }) .move({ origin: slider }) .press() .move({ x: offset, y: 0 }) .release() .perform();
// Alternative: Set value directly via JavaScriptawait driver.executeScript("arguments[0].value = 75", slider);await driver.executeScript("arguments[0].dispatchEvent(new Event('change'))", slider);
// Verify valueconst value = await slider.getAttribute('value');console.log(`Slider value: ${value}`);// Find the sliderIWebElement slider = driver.FindElement(By.Id("price-slider"));
// Get slider dimensionsint width = slider.Size.Width;
// Move slider to 75% positionint offset = (int)(width * 0.75) - (width / 2);new Actions(driver) .ClickAndHold(slider) .MoveByOffset(offset, 0) .Release() .Perform();
// Alternative: Set value directly via JavaScriptIJavaScriptExecutor js = (IJavaScriptExecutor)driver;js.ExecuteScript("arguments[0].value = 75", slider);js.ExecuteScript("arguments[0].dispatchEvent(new Event('change'))", slider);
// Verify valuestring value = slider.GetAttribute("value");Console.WriteLine($"Slider value: {value}");Troubleshooting Drag and Drop
| Issue | Solution |
|---|---|
| Actions don’t work | Try HTML5 JavaScript approach |
| Drop not registering | Add pauses during drag |
| Element moves back | Ensure proper drop zone detection |
| Offset is wrong | Calculate from element center |
| Animations interfere | Wait for animations to complete |
Best Practices
- Start with Actions API - simplest approach
- Fall back to JavaScript for HTML5 drag and drop
- Add pauses during drag operations
- Scroll elements into view before dragging
- Verify the result after drop
Next Steps
- Mouse Actions - Other mouse interactions
- JavaScript Executor - Advanced DOM manipulation
- Explicit Waits - Wait for drag effects