Skip to content

Dragging item across gap fails when using justify-content: space-between between drop zones #284

@Tiramisupxl

Description

@Tiramisupxl

Environment:

  • Vue version: 3.5.12
  • Vue.Draggable version: 4.1.0
  • Browser: chrome 135.0.7049.85

Problem Description:

I have a layout with a source list (using draggable) and a main content area. Inside the main content area (.canvas__content), there are two distinct drop zones (.canvas__section--left and .canvas__section--right), each containing a draggable component configured to accept items from the same group.

The parent container (.canvas__content) uses display: flex; justify-content: space-between; to position the left drop zone at the start and the right drop zone at the end, creating a visual gap between them.

When I try to drag an item from the source list across this middle gap to drop it into the right drop zone (.canvas__section--right), the drop operation fails. It seems like the right drop zone isn't recognized as a valid target, or the drag state gets interrupted when the mouse pointer moves over the empty space created by justify-content: space-between.

Dragging from the source list to the left drop zone (.canvas__section--left) works correctly. Also, if I remove justify-content: space-between; from the .canvas__content container (so the zones are adjacent), dragging to the right zone works as expected.

This issue is particularly noticeable during longer drag operations that inevitably cross the gap between the two drop zones.

Steps to Reproduce:

  1. Set up a draggable source list (e.g., pull: 'clone', put: false).
  2. Create a container element styled with display: flex; justify-content: space-between; width: [some significant width];.
  3. Inside this container, place two separate elements, each containing a draggable component configured with the same group name as the source list (e.g., group: 'items'). Style these elements so they are positioned at the far left and far right due to space-between.
  4. Attempt to drag an item from the source list.
  5. Move the dragged item across the empty space in the middle of the flex container towards the second (right) drop zone.
  6. Try to drop the item into the second drop zone.

Code Example:

(Please try to create a Minimal Reproducible Example (MRE) using CodeSandbox, StackBlitz, or a similar service. This is the most helpful way for maintainers to diagnose the issue. You can adapt the relevant parts of your code provided earlier.)

Link to Minimal Reproducible Example: [Link to CodeSandbox/StackBlitz]

Simplified Structure (based on provided code):

<template>
  <div class="container">
    <!-- Source List -->
    <div class="source-list">
      <draggable :list="sourceItems" :group="{ name: 'items', pull: 'clone', put: false }" item-key="id">
        <template #item="{ element }">
          <div class="source-item">{{ element.name }}</div>
        </template>
      </draggable>
    </div>

    <!-- Main Area with Drop Zones -->
    <div class="main-area">
       <!-- This is the container causing the issue -->
      <div class="canvas__content">
        <!-- Left Drop Zone -->
        <section class="canvas__section canvas__section--left">
          <draggable v-model="leftItems" group="items" item-key="id" class="dropzone">
            <template #item="{ element }">
              <div class="dropped-item">{{ element.name }} (Left)</div>
            </template>
             <!-- Placeholder for empty state -->
             <template #header>
                <div v-if="leftItems.length === 0" class="placeholder">Drop Left</div>
             </template>
          </draggable>
        </section>

        <!-- Right Drop Zone -->
        <section class="canvas__section canvas__section--right">
          <draggable v-model="rightItems" group="items" item-key="id" class="dropzone">
            <template #item="{ element }">
              <div class="dropped-item">{{ element.name }} (Right)</div>
            </template>
            <!-- Placeholder for empty state -->
            <template #header>
               <div v-if="rightItems.length === 0" class="placeholder">Drop Right</div>
            </template>
          </draggable>
        </section>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue';
import draggable from 'vuedraggable';

const sourceItems = ref([ { id: 1, name: 'Item 1' }, { id: 2, name: 'Item 2' } ]);
const leftItems = ref([]);
const rightItems = ref([]);
</script>

<style>
.container { display: flex; }
.source-list { width: 200px; border-right: 1px solid #ccc; padding: 10px; }
.source-item { border: 1px solid #eee; padding: 5px; margin-bottom: 5px; background: #f9f9f9; cursor: grab; }
.main-area { flex: 1; padding: 20px; }

.canvas__content {
  display: flex;
  justify-content: space-between; /* This is the key style causing the issue */
  border: 1px dashed blue;
  padding: 10px;
  min-height: 300px; /* Ensure space */
}

.canvas__section {
  width: 45%; /* Example width */
  border: 1px solid green;
}

.dropzone {
  border: 2px dashed #ccc;
  min-height: 280px; /* Ensure drop target area */
  padding: 10px;
  background-color: #f0f0f0;
}

.dropped-item {
  border: 1px solid #aaa;
  background: lightblue;
  padding: 5px;
  margin-bottom: 5px;
}
.placeholder { color: #aaa; text-align: center; padding: 20px; }
</style>

Expected Behavior:

When dragging an item from the source list, I should be able to drop it into either the left or the right drop zone. The right drop zone should become active/highlighted as a valid target even when the cursor crosses the empty space created by justify-content: space-between.

Actual Behavior:

When dragging an item across the empty space towards the right drop zone, the right drop zone does not consistently register as a valid drop target. The drop often fails, and the item returns to the source list, or the UI doesn't indicate it's a valid target.

(Optional) Possible Workaround Found:

Removing justify-content: space-between from the .canvas__content container resolves the issue, but breaks the required layout. Another potential workaround involves making the .canvas__content container itself a draggable with :put="false", acting as a bridge.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions