- Use the Dart drag and drop library instead (better, without HTML5).
- Read the details about why I chose Drag and Drop without HTML5
- Make any HTML Element
draggable
. - Create
dropzones
and connect them withdraggables
. - Rearrange elements with
sortables
(similar to jQuery UI Sortable). - Support for
touch events
on touch screen devices. - Same functionality and API for IE9+, Firefox, Chrome and Safari.
- Uses fast native HTML5 Drag and Drop of the browser whenever possible.
- For browsers that do not support some features, the behaviour is emulated. This is the case for IE9 and partly for IE10 (when custom drag images are used).
See the demo page above or the example
directory to see some live examples
with code.
In general, to make drag and drop work, we will have to do two things:
- Create draggables by installing HTML elements in a
DraggableGroup
. - Create dropzones by installing HTML elements in a
DropzoneGroup
.
To make elements sortable it's even easier: Create sortables by installing HTML
elements in a SortableGroup
. The SortableGroup
will make the installed
elements both into draggables and dropzones and thus creates sortable behaviour.
There is a global property called enableTouchEvents
which is true
by
default. This means that touch events are automatically enabled on devices that
support it. If touch support should not be used even on touch devices, set this
flag to false
.
Any HTML element can be made draggable. First we'll have to create a
DraggableGroup
that manages draggable elements. The DraggableGroup
holds
all options for dragging and provides event streams we can listen to.
This is how a DraggableGroup
is created. With install(...)
or
installAll(...)
elements are made draggable and registered in the group.
// Creating a DraggableGroup and installing some elements.
DraggableGroup dragGroup = new DraggableGroup();
dragGroup.installAll(queryAll('.my-draggables'));
With uninstall(...)
or uninstallAll(...)
draggables can be removed from
the group and the draggable behaviour is uninstalled.
The DraggableGroup
has three constructor options:
- The
dragImageFunction
is used to provide a customDragImage
. If nodragImageFunction
is supplied, the drag image is created from the HTML element of the draggable. - If a
handle
is provided, it is used as query String to find subelements of draggable elements. The drag is then restricted to those elements. - If
cancel
is provided, it is used as query String to find a subelement of drabbable elements. The drag is then prevented on those elements. The default is 'input,textarea,button,select,option'.
// Create a custom drag image from a png.
ImageElement png = new ImageElement(src: 'icons/smiley-happy.png');
DragImage img = new DragImage(png, 0, 0);
// Always return the same DragImage here. We could also create a different image
// for each draggable.
DragImageFunction imageFunction = (Element draggable) {
return img;
};
// Create DraggableGroup with custom drag image and a handle.
DraggableGroup dragGroupHandle = new DraggableGroup(
dragImageFunction: imageFunction, handle: '.my-handle');
// Create DraggableGroup with a cancel query String.
DraggableGroup dragGroupCancel = new DraggableGroup(
cancel: 'textarea, button, .no-drag');
Other options of the DraggableGroup
:
DraggableGroup dragGroup = new DraggableGroup();
// CSS class set to html body during drag.
dragGroup.dragOccurringClass = 'dnd-drag-occurring';
// CSS class set to the draggable element during drag.
dragGroup.draggingClass = 'dnd-dragging';
// CSS class set to the dropzone when a draggable is dragged over it.
dragGroup.overClass = 'dnd-over';
// Changes mouse cursor when this draggable is dragged over a draggable.
dragGroup.dropEffect = DROP_EFFECT_COPY;
We can listen to dragStart
, drag
, and dragEnd
events of a
DraggableGroup
.
DraggableGroup dragGroup = new DraggableGroup();
dragGroup.onDragStart.listen((DraggableEvent event) => print('drag started'));
dragGroup.onDrag.listen((DraggableEvent event) => print('dragging'));
dragGroup.onDragEnd.listen((DraggableEvent event) => print('drag ended'));
Any HTML element can be made to a dropzone. Similar to how draggables are created, we create a dropzones:
// Creating a DropzoneGroup and installing some elements.
DropzoneGroup dropGroup = new DropzoneGroup();
dropGroup.installAll(queryAll('.my-dropzones'));
The DropzoneGroup
has an option to specify which DraggableGroup
s it accepts.
If no accept group is specified, the DropzoneGroup
will accept all draggables.
DraggableGroup dragGroup = new DraggableGroup();
// ... install some draggable elements ...
DropzoneGroup dropGroup = new DropzoneGroup();
// ... install some dropzone elements ...
// Make dropGroup only accept draggables from dragGroup.
dropGroup.accept.add(dragGroup);
We can listen to dragEnter
, dragOver
, dragLeave
, and drop
events of a
DropzoneGroup
.
DropzoneGroup dropGroup = new DropzoneGroup();
dropGroup.onDragEnter.listen((DropzoneEvent event) => print('drag entered'));
dropGroup.onDragOver.listen((DropzoneEvent event) => print('dragging over'));
dropGroup.onDragLeave.listen((DropzoneEvent event) => print('drag left'));
dropGroup.onDrop.listen((DropzoneEvent event) => print('dropped inside'));
For reordering of HTML elements we can use sortables.
// Creating a SortableGroup and installing some elements.
SortableGroup sortGroup = new SortableGroup();
sortGroup.installAll(queryAll('.my-sortables'));
Note: All sortables are at the same time draggables and dropzones. This means
we can set all options of DraggableGroup
and DropzoneGroup
on sortables and
listen to all their events.
In addition to the inherited DraggableGroup
and DropzoneGroup
options,
SortableGroup
has the following options:
SortableGroup sortGroup = new SortableGroup();
// CSS class set to placeholder element.
sortGroup.placeholderClass = 'dnd-placeholder';
// If true, forces the placeholder to have the computed size of the dragged element.
sortGroup.forcePlaceholderSize = true;
// Must be set to true for sortable grids. This ensures that different sized
// items in grids are handled correctly.
sortGroup.isGrid = false;
Next to the inherited DraggableGroup
and DropzoneGroup
events
SortableGroup
has one additional event:
SortableGroup sortGroup = new SortableGroup();
sortGroup.onSortUpdate.listen((SortableEvent event) => print('elements were sorted'));
I'd like to thank the people who kindly helped me with their answers or put some tutorial or code examples online. They've indirectly contributed to this project.
If you'd like to contribute, you're welcome to report issues or fork my repository on GitHub.
The MIT License (MIT)