Skip to main content
SeleniumDecoded

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 action
Actions actions = new Actions(driver);
actions.dragAndDrop(source, target).perform();
// Method 2: Explicit steps
actions.clickAndHold(source)
.moveToElement(target)
.release()
.perform();
// Method 3: With offset
actions.dragAndDropBy(source, 100, 50).perform(); // Move by x, y pixels
from 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 action
actions = ActionChains(driver)
actions.drag_and_drop(source, target).perform()
# Method 2: Explicit steps
actions = ActionChains(driver)
actions.click_and_hold(source) .move_to_element(target) .release() .perform()
# Method 3: With offset
actions = ActionChains(driver)
actions.drag_and_drop_by_offset(source, 100, 50).perform() # Move by x, y
// Method 1: Using actions
const 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 steps
await driver.actions({ async: true })
.move({ origin: source })
.press()
.move({ origin: target })
.release()
.perform();
// Method 3: With offset
await 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 action
Actions actions = new Actions(driver);
actions.DragAndDrop(source, target).Perform();
// Method 2: Explicit steps
new Actions(driver)
.ClickAndHold(source)
.MoveToElement(target)
.Release()
.Perform();
// Method 3: With offset
new Actions(driver)
.DragAndDropToOffset(source, 100, 50)
.Perform(); // Move by x, y pixels

Handling 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 JavaScript
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);
source = driver.find_element(By.ID, "drag-source")
target = driver.find_element(By.ID, "drop-target")
# Simulate drag and drop with custom JavaScript
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]);
"""
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 JavaScript
const 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 1
List<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 order
List<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 1
items = 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 order
reordered_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 1
const 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 order
const 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 1
IList<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 order
IList<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 moved
WebElement 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 moved
moved_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 moved
const 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 moved
IWebElement 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 slider
WebElement slider = driver.findElement(By.id("price-slider"));
// Get slider dimensions
int width = slider.getSize().getWidth();
// Move slider to 75% position
Actions actions = new Actions(driver);
actions.clickAndHold(slider)
.moveByOffset((int)(width * 0.75) - (width / 2), 0)
.release()
.perform();
// Alternative: Set value directly via JavaScript
JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeScript("arguments[0].value = 75", slider);
js.executeScript("arguments[0].dispatchEvent(new Event('change'))", slider);
// Verify value
String value = slider.getAttribute("value");
System.out.println("Slider value: " + value);
# Find the slider
slider = driver.find_element(By.ID, "price-slider")
# Get slider dimensions
width = slider.size['width']
# Move slider to 75% position
actions = 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 JavaScript
driver.execute_script("arguments[0].value = 75", slider)
driver.execute_script("arguments[0].dispatchEvent(new Event('change'))", slider)
# Verify value
value = slider.get_attribute("value")
print(f"Slider value: {value}")
// Find the slider
const slider = await driver.findElement(By.id('price-slider'));
// Get slider dimensions
const size = await slider.getRect();
const width = size.width;
// Move slider to 75% position
const 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 JavaScript
await driver.executeScript("arguments[0].value = 75", slider);
await driver.executeScript("arguments[0].dispatchEvent(new Event('change'))", slider);
// Verify value
const value = await slider.getAttribute('value');
console.log(`Slider value: ${value}`);
// Find the slider
IWebElement slider = driver.FindElement(By.Id("price-slider"));
// Get slider dimensions
int width = slider.Size.Width;
// Move slider to 75% position
int offset = (int)(width * 0.75) - (width / 2);
new Actions(driver)
.ClickAndHold(slider)
.MoveByOffset(offset, 0)
.Release()
.Perform();
// Alternative: Set value directly via JavaScript
IJavaScriptExecutor js = (IJavaScriptExecutor)driver;
js.ExecuteScript("arguments[0].value = 75", slider);
js.ExecuteScript("arguments[0].dispatchEvent(new Event('change'))", slider);
// Verify value
string value = slider.GetAttribute("value");
Console.WriteLine($"Slider value: {value}");

Troubleshooting Drag and Drop

IssueSolution
Actions don’t workTry HTML5 JavaScript approach
Drop not registeringAdd pauses during drag
Element moves backEnsure proper drop zone detection
Offset is wrongCalculate from element center
Animations interfereWait for animations to complete

Best Practices

  1. Start with Actions API - simplest approach
  2. Fall back to JavaScript for HTML5 drag and drop
  3. Add pauses during drag operations
  4. Scroll elements into view before dragging
  5. Verify the result after drop

Next Steps