Implementation:Teamcapybara Capybara Html5 Drag
| Knowledge Sources | |
|---|---|
| Domains | Testing, Browser_Interaction |
| Last Updated | 2026-02-12 00:00 GMT |
Overview
Concrete tool for emulating HTML5 drag-and-drop operations via JavaScript injection, provided by Capybara::Selenium::Node::Html5Drag.
Description
Capybara::Selenium::Node::Html5Drag is a module included by browser-specific node classes (ChromeNode, EdgeNode) to provide drag-and-drop support that works around WebDriver limitations with HTML5 draggable elements.
The main entry point drag_to first installs a MOUSEDOWN_TRACKER script that records whether mousedown was prevented. It then performs a click_and_hold via the browser action API. If the html5 parameter is nil, the LEGACY_DRAG_CHECK script determines at runtime whether the source element (or any ancestor) has the draggable attribute and whether mousedown was prevented -- if so, a legacy (non-HTML5) drag is used.
perform_legacy_drag uses the Selenium ActionBuilder to move to the target element while applying modifier keys, then releases. perform_html5_drag executes the HTML5_DRAG_DROP_SCRIPT, a large async JavaScript function that synthesizes the full HTML5 drag event sequence: dragstart on the source, then after a configurable delay, dragenter on the target, two dragover events (simulating directional movement using rectCenter and pointOnRect geometry helpers), dragleave, conditionally drop (if dragover was not prevented), and finally dragend.
html5_drop handles programmatic drops of files or string data. For file drops, it creates a hidden file input via ATTACH_FILE, sets files on it, then dispatches a drop event using DROP_FILE. For string data, DROP_STRING constructs a DataTransfer object and dispatches the drop event directly.
The module contains six JavaScript constants: DROP_STRING, DROP_FILE, ATTACH_FILE, MOUSEDOWN_TRACKER, LEGACY_DRAG_CHECK, and HTML5_DRAG_DROP_SCRIPT.
Usage
Called automatically when element.drag_to(target) is invoked on a Chrome or Edge node. The html5 parameter can force HTML5 mode (true) or legacy mode (false), or auto-detect (nil). drop_modifiers accepts modifier key symbols applied during the drop phase.
Code Reference
Source Location
- Repository: capybara
- File: lib/capybara/selenium/extensions/html5_drag.rb
- Lines: 229
Signature
class Capybara::Selenium::Node
module Html5Drag
def drag_to(element, html5: nil, delay: 0.05, drop_modifiers: [])
# @param element [Capybara::Selenium::Node] Target element to drag to
# @param html5 [Boolean, nil] Force HTML5 drag (true), legacy drag (false), or auto-detect (nil)
# @param delay [Float] Delay in seconds between drag event phases (default: 0.05)
# @param drop_modifiers [Symbol, Array<Symbol>] Modifier keys to hold during drop
end
def html5_drop(*args)
# @param args [Array<String>, Array<Hash>] File paths or type/data pairs for drop
# Dispatches drop event with files or string data
end
# Private methods
# perform_legacy_drag(element, drop_modifiers) - ActionBuilder-based drag
# perform_html5_drag(element, delay, drop_modifiers) - JavaScript-based HTML5 drag
end
end
Import
require 'capybara/selenium/extensions/html5_drag'
# Included by ChromeNode and EdgeNode
I/O Contract
Inputs
| Name | Type | Required | Description |
|---|---|---|---|
| element | Capybara::Selenium::Node | Yes | The target element to drag to |
| html5 | Boolean/nil | No | Force HTML5 drag (true), legacy drag (false), or auto-detect (nil, default) |
| delay | Float | No | Seconds between drag event phases (default: 0.05) |
| drop_modifiers | Symbol/Array<Symbol> | No | Modifier keys (e.g., :control, :shift) applied during drop (default: []) |
| args (html5_drop) | Array<String>/Array<Hash> | Yes | File paths for file drop, or [[type, data], ...] pairs for string data drop |
Outputs
| Name | Type | Description |
|---|---|---|
| (side effect) | nil | Drag events are dispatched in the browser; no Ruby return value |
Usage Examples
Basic Drag and Drop
source = page.find('#draggable')
target = page.find('#droppable')
# Auto-detect HTML5 vs legacy drag
source.drag_to(target)
# Force HTML5 drag with longer delay
source.drag_to(target, html5: true, delay: 0.1)
# Drag with modifier keys held during drop
source.drag_to(target, drop_modifiers: [:control])
Programmatic File Drop
drop_zone = page.find('#file-drop-zone')
# Drop files onto an element
drop_zone.drop('/path/to/file1.txt', '/path/to/file2.txt')
Programmatic String Data Drop
drop_zone = page.find('#data-drop-zone')
# Drop string data with MIME types
drop_zone.drop(['text/plain', 'Hello World'], ['text/html', '<b>Bold</b>'])