Creating a Drag Source
- Making a Component Draggable
- Exposing Drag Source API to a Component
- Assigning Server-Side Data to Drag Source
- Drag Start & End Events
- Customizing the Draggable Element
- Customizing the Drag Image
With the DragSource class, you can make any component draggable by the user, and configure the drag operation for it. By default, the entire component is made draggable. You can also make only a portion of the component draggable, this is covered later.
Making a Component Draggable
The DragSource class is a configuration object for the dragged item and contains static methods for configuring the given component instance.
Div components draggable in different waysSource code
Java
Div box1 = new Div();
Div box2 = new Div();
// Make box 1 draggable and store reference to the configuration object.
DragSource<Div> box1DragSource = DragSource.create(box1);
// Access box 2 drag related configuration object without making it draggable.
DragSource<Div> box2DragSource = DragSource.configure(box2);
// Make box 2 draggable.
box2DragSource.setDraggable(true);
add(box1, box2);The DragSource configuration object doesn’t itself store any data, as it’s a convenience proxy that facilitates making a component draggable. Creating a new DragSource instance of a component doesn’t reset any previous configuration, but any changes override the previous configuration.
When a component is set as draggable on the server side, the draggable attribute is assigned to its topmost element on the browser, thus making it draggable. When the user starts to drag the component, the root element of the component gets the v-dragged class name in the browser. This can be used to highlight the dragged component to the user.
Source code
CSS
.v-dragged {
outline: 1px dotted hotpink;
opacity: 0.5;
}Exposing Drag Source API to a Component
As the DragSource is an interface, it can also be used as a mixin interface. It provides an easy way to add its API to your custom component. This is convenient when you want to reuse the component in many places for drag operation.
CardComponent draggable by defaultSource code
Java
public class CardComponent extends Div implements DragSource<CardComponent>, HasStyle {
public CardComponent() {
// all cards are draggable by default
setDraggable(true);
}
// all DragSource methods have default implementations
}See Using Vaadin Mixin Interfaces reference guide for more information about mixin interfaces.
Assigning Server-Side Data to Drag Source
You can set any Java object as the server-side drag data for the drag source. When a drop occurs on a valid drop target within the same UI (browser window or tab) as the drag source component, this data is available from the DropEvent.
CardComponent instances with different types of drag dataSource code
Java
// Continuing from the previous example, CardComponent implements DragSource.
CardComponent card1 = new CardComponent();
CardComponent card2 = new CardComponent();
card1.setDragData("Queen of Hearts");
card2.setDragData(new Card(11, Land.Spade)); // The data can be any object.The data isn’t sent to the browser, as it’s stored in the component instance as server-side-only data.
It isn’t possible to configure the client-side drag data, the dataTransfer object, from the server side.
Drag Start & End Events
The DragSource provides a way to react when the user starts and stops dragging a component. The DragStartEvent is fired when the drag starts in the browser, which means that you can’t cancel the drag. You should avoid doing any heavy synchronous processing there, since this blocks the user from dragging the component further in the browser. That would have a negative effect on the UX.
Source code
Java
// Continuing from the previous example with CardComponent.
card1.addDragStartListener(event -> {
// Highlight suitable drop targets in the UI
getVisibleCards().forEach(target -> {
Card targetCard = target.getCard();
if (targetCard.getLand() == ((Card) card1.getDragData()).getLand()
&& target != card1) {
target.addClassName("possible-drop-zone");
}
})
});When the user stops dragging the component by either dropping it or by canceling the drag with, for example, the escape key, the DragEndEvent is fired. The isSuccessful() method returns true if the drop occurred on a drop target that accepted the drop, but only for Chrome and Firefox (see the note after the example below).
Source code
Java
card1.addDragEndListener(event -> {
getVisibleCards().forEach(target -> target.removeClassName("possible-drop-zone"));
// NOTE: The following is always FALSE for Edge and Safari !!!
if (event.isSuccessful()) {
// Better to put logic for successful drop into DropEvent for the
// DropTarget because of the above.
}
});|
Important
|
Handling Drag End in Edge & Safari
Edge and Safari don’t report whether the drop occurred successfully in the DragEnd event. You’ll need to take this into account if your users are using any of these browsers, and do any logic in the DropEvent handler of the DropTarget, instead. For Chrome and Firefox, it works correctly. See the Creating a Drop Target reference guide for more information about handling drop events.
|
Effect Allowed & Drop Effect
The drag source’s effectAllowed property defines which drop operations (copy, move, link) are permitted for that element. The drop target’s dropEffect property specifies which single operation it wants to perform. These properties work together to control both the visual cursor feedback during dragging and the final operation performed.
The browser determines the final dropEffect through this process:
-
The drop target requests a specific
dropEffect(copy, move, or link) -
The browser checks if this effect is permitted by the drag source’s
effectAllowed -
The user can override using modifier keys (such as Ctrl for copy, Shift for move, etc.)
-
If there’s no match, the
dropEffectbecomesNONEand the drop is cancelled
The DragEndEvent reports the final dropEffect that was applied.
When the drop effect is MOVE, you should remove or relocate the drag source component from its original location. When the drop effect is NONE, the drop was cancelled and dropEvent.isSuccessful() returns false.
Customizing the Draggable Element
You can customize the element that is made draggable by overriding the getDraggableElement() method in the DragSource interface. This is useful if it’s not the whole component that’s to be draggable, but only a part of it.
RouteItem component draggableSource code
Java
/* NOTE: RouteItem is a made up custom component, not a core Vaadin component. */
public class DraggableRouteItem extends RouteItem implements DragSource<RouteItem> {
private Icon dragHandle = VaadinIcon.MENU.create();
public DraggableRouteItem(String destination) {
super(destination);
add(dragHandle);
}
// Instead of allowing the whole item to be draggable, only allow dragging
// from the icon.
@Override
public Element getDraggableElement() {
return dragHandle.getElement();
}
}Changing the draggable element also changes the drag image that the browser shows under the cursor.
Customizing the Drag Image
The DragSource interface provides setDragImage() methods to customize the drag image shown under the cursor during dragging.
Using Image
The Image component is the recommended and fully supported option for drag images.
Source code
Java
// Continuing from the previous example
CardComponent card = new CardComponent();
card.setDragImage(new Image("/cards/ace_of_spades.png", "Ace of Spades"));The Image component supports DownloadHandler for dynamic image generation.
You can specify the cursor’s position relative to the drag image by providing x and y offsets from the image’s top-left corner:
Source code
Java
card.setDragImage(new Image("/cards/queen_of_hearts.png", "Queen of Hearts"), 20, 0);Using Other Components
Components other than Image can be used as drag images, with these considerations:
-
Visible components: If the component is already visible in the viewport, the browser uses it directly as the drag image
-
Off-screen components: Components not in the viewport must be added to the DOM as off-screen elements. Vaadin handles this automatically when you call
setDragImage()with an unattached component
To customize the positioning or styling of an off-screen drag image component, add it to the DOM manually before calling setDragImage().
Span as a drag image by adding it off-screenSource code
Java
Span dragImage = new Span("Drag Image Component");
Style dragImageStyle = dragImage.getElement().getStyle();
dragImageStyle.setPosition(Style.Position.ABSOLUTE);
dragImageStyle.setTop("-100px"); 1
dragImageStyle.setLeft("-100px");
dragImageStyle.setDisplay(Style.Display.NONE); 2
add(dragImage);
dragSource.setDragImage(dragImage);-
Positioning the component off-screen prevents it from being visible to the user.
-
Setting
display: noneensures the component doesn’t affect layout or visibility.
|
Note
| Browser support for non-Image components as drag images varies. Test your implementation across target browsers. |
For more information, see the HTML5 Drag & Drop API.
4FFD51BA-4736-44BD-8FCF-0E534A19FB8D