Documentation

Report Edit

Drag & Drop

import {DragSource, DropZone} from 'cx/widgets';

Drag & drop functionality is provided through DragSource and DropZone widgets, while Grid supports dropping and its rows behave like drag sources.

Drag & drop can be used in many different ways. Let's go through a few common scenarios. Links to advanced examples are provided at the end.

Fixed Positions

The simplest case is when drag sources and drop zones are completely independent.

In the following example, there are two drag sources (B1 and B2) and one drop zone (Z1). Sources can be dragged around and dropped on drop zones. Each source should define its data that drop zones use to test if drop should be allowed and, when the drop occurs, to execute appropriate actions.

B1
B2
Z1
Index
<DragSource
    style="width:80px;height:80px;background:LightSeaGreen;cursor:move"
    data={{text: 'B1', type: 'b1'}}
>
    B1
</DragSource>
<DragSource
    style="width:80px;height:80px;background:Coral;cursor:move"
    data={{text: 'B2', type: 'b2'}}
    cloneStyle="border: 1px solid gray; padding: 10px; transform: scale(0.5)"
>
    B2
</DragSource>
<DropZone
    style="width:80px;height:80px;background:gold;opacity:0.3;transition: all 0.2s"
    overStyle="background:lightgreen;opacity:1"
    farStyle="opacity:1"
    onDropTest={({source}) => source.data.type == 'b1'}
    onDrop={({source}) => {
        MsgBox.alert(`Dropped: ${source.data.text}.`);
    }}
    inflate={20}
>
    Z1
</DropZone>
Copied!Cx Fiddle

During drag & drop operations drop zones should make visual changes to indicate to the user that drop is allowed.

Drag Handles

Drag handles are useful for dragging larger chunks of UI.

DRAG USING THIS HANDLE
Index
<DragSource
    style="width: 180px;height:180px;background:moccasin;padding:15px"
    data={{type: 'b1', text: 'Box with a drag handle'}}
    handled
>
    <DragHandle style="background:LightSeaGreen;padding:5px;cursor:move;font-size:10px">
        DRAG USING THIS HANDLE
    </DragHandle>
</DragSource>
Copied!

Reordering allows users to define order within a list of items.

The following example explains reordering of items positioned horizontally (e.g. tabs). This is enabled by putting drop zones in gaps between drag sources. When dragging starts, the source is hidden and its place is occupied by the nearest drop zone. This is achieved using the matchWidth, matchHeight, and matchMargin flags. Each drop zone is inflated so it reacts when mouse is in its proximity, not strictly when it's over.

Item 1
Item 2
Item 3
Item 4
Item 5
Item 6
Item 7
Index
<DropZone
    mod="inline-block"
    onDropTest={({source}) => source.data.type == 'hbox'}
    onDrop={(e, {store}) => {
        store.update('items', moveElement, e.source.data.index, 0);
    }}
    matchWidth
    matchHeight
    matchMargin
    inflate={50}
>
</DropZone>
<Repeater
    keyField="id"
    records={{
        bind: 'items', defaultValue: Array.from({length: 7}, (_, i) => ({
            id: i + 1,
            text: `Item ${i + 1}`
        }))
    }}
>
    <DragSource
        style="display:inline-block; margin: 5px; background: #ddf; cursor: move"
        data={{index: {bind: "$index"}, type: 'hbox'}}
        hideOnDrag
    >
        <div text-bind="$record.text" style="padding:5px"/>
    </DragSource>
    <DropZone
        mod="inline-block"
        onDropTest={({source}) => source.data.type == 'hbox'}
        onDrop={(e, {store}) => {
            store.update('items', moveElement, e.source.data.index, store.get('$index') + 1);
        }}
        matchWidth
        matchHeight
        matchMargin
        inflate={50}
    >
    </DropZone>
</Repeater>
Copied!Cx Fiddle

Advanced Examples

Check out the following examples to learn more about drag & drop capabilites in CxJS.

Configuration

DragSourceDropZoneDragDropEvent

PropertyDescriptionType
data

Data about the drag source that can be used by drop zones to test if drag source is acceptable and to perform drop operations.

object
handled

Set to true to indicate that the drag source can be dragged only by using an inner DragHandle.

string
hideOnDrag

Set to true to hide the element while being dragged. Use if drop zones are configured to expand in order to indicate where drop will occur.

boolean
onDragEnd

A callback invoked when drag operation completes. Arguments are event and instance.

function
onDragStart

A callback invoked when drag operation starts. Arguments are event and instance. If the function returns false, drag operation is canceled.

function
baseClass

Base CSS class to be applied to the element. Default value is dragsource.

string
class
className

Additional CSS classes to be applied to the element. If an object is provided, all keys with a "truthy" value will be added to the CSS class list.

string/object
clone

Custom contents to be displayed during drag & drop operation.

config
cloneClass

Additional CSS class to be applied to the drag clone element.

string
cloneStyle

Additional style rules to be applied to the drag clone element.

string
items
children

List of child elements.

array
layout

Define an inner layout.

string/object
mod

Appearance modifier. For example, mod="big" will add the CSS class .cxm-big to the block element.

string/array
outerLayout

Defines the outer layout which wraps the widget.

widget
plainText

Set to true to avoid converting inner strings to templates. Default is false.

boolean
preserveWhitespace
ws

Keep whitespace in text based children. Default is false. See also trimWhitespace.

boolean
putInto
contentFor

Used with outer layouts. Specifies the name of the content placeholder which should render the widget.

string
style

Style object applied to the wrapper div. Used for setting the dimensions of the element.

string/object
trimWhitespace

Remove all whitespace in text based children. Default is true. See also preserveWhitespace.

boolean
vdomKey

Key that will be used as the key when rendering the React component.

string
visible
if

Visibility of the widget. Defaults to true.

boolean