CxJS

DropZone

import { DropZone } from 'cx/widgets'; Copied

DropZone defines areas where dragged items can be dropped. The onDrop callback receives the dropped data and allows you to handle the drop action.

Example

This example demonstrates onDropTest to restrict which items can be dropped in each zone. Fruits and Vegetables zones only accept matching types, while Anything accepts all items.

<div class="flex gap-4" controller={PageController}>
  <DropZone
    class="flex flex-col gap-2 p-4 border rounded min-w-32 min-h-32 bg-gray-50"
    overClass="!bg-green-50 !border-green-300"
    onDropTest={({ source }) => source.data.type === "fruit"}
    onDrop={({ source }, { store }) => {
      removeItem(store, source.data)
      store.set(m.fruits, [...store.get(m.fruits), source.data])
    }}
  >
    <div class="text-sm font-medium mb-2">Fruits</div>
    <div class="flex flex-col gap-1 min-h-16">
      <Repeater records={m.fruits} recordAlias={m.$fruit} keyField="name">
        <DragSource data={m.$fruit}>
          <div class="p-2 border rounded bg-white cursor-move">
            <span text={m.$fruit.name} />
          </div>
        </DragSource>
      </Repeater>
    </div>
  </DropZone>

  <DropZone
    class="flex flex-col gap-2 p-4 border rounded min-w-32 min-h-32 bg-gray-50"
    overClass="!bg-orange-50 !border-orange-300"
    onDropTest={({ source }) => source.data.type === "vegetable"}
    onDrop={({ source }, { store }) => {
      removeItem(store, source.data)
      store.set(m.vegetables, [...store.get(m.vegetables), source.data])
    }}
  >
    <div class="text-sm font-medium mb-2">Vegetables</div>
    <div class="flex flex-col gap-1 min-h-16">
      <Repeater
        records={m.vegetables}
        recordAlias={m.$vegetable}
        keyField="name"
      >
        <DragSource data={m.$vegetable}>
          <div class="p-2 border rounded bg-white cursor-move">
            <span text={m.$vegetable.name} />
          </div>
        </DragSource>
      </Repeater>
    </div>
  </DropZone>

  <DropZone
    class="flex flex-col gap-2 p-4 border rounded min-w-32 min-h-32 bg-gray-50"
    overClass="!bg-blue-50 !border-blue-300"
    onDrop={({ source }, { store }) => {
      removeItem(store, source.data)
      store.set(m.anything, [...store.get(m.anything), source.data])
    }}
  >
    <div class="text-sm font-medium mb-2">Anything</div>
    <div class="flex flex-col gap-1 min-h-16">
      <Repeater records={m.anything} recordAlias={m.$item} keyField="name">
        <DragSource data={m.$item}>
          <div class="p-2 border rounded bg-white cursor-move">
            <span text={m.$item.name} />
          </div>
        </DragSource>
      </Repeater>
    </div>
  </DropZone>
</div>
Fruits
Apple
Banana
Vegetables
Carrot
Broccoli
Anything

Sizing Options

Control how the drop zone matches its content:

<DropZone
  matchWidth // Match the width of the child element
  matchHeight // Match the height of the child element
  matchMargin // Include margins when calculating dimensions
  inflate={5} // Expand the drop zone by 5 pixels
>
  <div>Content</div>
</DropZone>

Block Mode

Use mod="block" for invisible drop zones used in list reordering. In block mode, the drop zone has a height of 1px and spans the full width. Use inflate to expand the hit area:

<DropZone mod="block" inflate={50} onDrop={handleDrop} />

Configuration

PropertyTypeDescription
dataPropBindable data related to the DropZone, available in callbacks.
onDropfunctionCallback invoked when an item is dropped.
onDropTestfunctionTest if dragged source is acceptable. Return false to reject.
onDragStartfunctionCallback invoked when any drag operation begins.
onDragEndfunctionCallback invoked when any drag operation ends.
onDragEnterfunctionCallback invoked when source enters the drop zone.
onDragLeavefunctionCallback invoked when source leaves the drop zone.
onDragOverfunctionCallback invoked continuously while source is over the zone.
onDragNearfunctionCallback invoked when source gets close to the zone.
onDragAwayfunctionCallback invoked when source moves away from the zone.
overStyleStyleCSS styles applied when cursor is over the drop zone.
overClassClassCSS class applied when cursor is over the drop zone.
nearStyleStyleCSS styles applied when cursor is near the drop zone.
nearClassClassCSS class applied when cursor is near the drop zone.
farStyleStyleCSS styles applied when drag begins to highlight drop zones.
farClassClassCSS class applied when drag begins to highlight drop zones.
nearDistancenumberDistance in pixels to consider the cursor “near”. Defaults to 0.
inflatenumberInflate bounding box by this many pixels in all directions.
hinflatenumberInflate bounding box horizontally.
vinflatenumberInflate bounding box vertically.
matchWidthbooleanMatch width of the item being dragged.
matchHeightbooleanMatch height of the item being dragged.
matchMarginbooleanMatch margin of the item being dragged.