Docs

Documentation versions (currently viewingVaadin 25 (prerelease))

Creating a Drag Source

Making any component draggable and configuring the drag operation.

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.

Example 1. Making two Div components draggable in different ways
Source 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.

Example 2. Painting a dotted outline around the dragged component with some transparency
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.

Example 3. Making a custom CardComponent draggable by default
Source 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.

Example 4. Making two draggable CardComponent instances with different types of drag data
Source 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.

Example 5. Highlighting suitable drop targets when dragging starts
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:

  1. The drop target requests a specific dropEffect (copy, move, or link)

  2. The browser checks if this effect is permitted by the drag source’s effectAllowed

  3. The user can override using modifier keys (such as Ctrl for copy, Shift for move, etc.)

  4. If there’s no match, the dropEffect becomes NONE and 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.

Example 6. Making only an icon within a custom RouteItem component draggable
Source 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.

Example 7. Setting an image of the Ace of Spades as the drag image
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:

Example 8. Positioning the cursor 20 pixels from left edge, aligned with top edge
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().

Example 9. Using a Span as a drag image by adding it off-screen
Source 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);
  1. Positioning the component off-screen prevents it from being visible to the user.

  2. Setting display: none ensures 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