# Drag and drop across apps

Offer and accept typed data with permissions, validation and a programmatic alternative to dragging.

This page describes WU Framework `4.0.0`. Read the [Framework 4.0 and CLI 1.2 migration guide](/docs/guides/releases/) before upgrading an existing project.

The shell imports `wu-framework/dnd` when using core. The sending app requests `drag.offer:catalog.product` and the receiving app requests `drag.accept:catalog.product`; the host grants each permission to its respective app. Use `context.wu` inside the lifecycle to retain each app authority.

```js
// Inside the sending app's async mount(container, props, context):
const card = document.createElement('button');
card.textContent = 'Product 42';
container.append(card);
const stopOffer = await context.wu.drag.offer(card, {
  type: 'catalog.product', payload: { id: '42', quantity: 1 },
});
// Save stopOffer and call it from this app's unmount.
```

```js
// Inside the receiving app's async mount(container, props, context):
const stopAccept = await context.wu.drop.accept(container, {
  type: 'catalog.product',
  validate(value) {
    if (typeof value?.id !== 'string') throw new TypeError('Product id is required');
    return value;
  },
  onDrop: product => { container.textContent = 'Added: ' + product.id; },
});
// Save stopAccept and call it from this app's unmount.
```

`offer()` and `accept()` return promises of cleanup functions. Retain them on the instance and invoke them on unmount. If an effect can be cancelled before the promise resolves, invoke the disposer immediately when it arrives for an already-cancelled effect.

`wu.drag.deliver(type, payload, { to, element })` performs the same delivery without physical dragging: use it for a keyboard or button action. `current()` returns the active session or `null`. Native transfer carries a session ID, not the entire object; the target receives a copy after permissions and validation pass. This coordinates data; it does not move DOM between apps.

Offers accept `effect`, `image` and `onEnd`. Targets accept multiple types, `onEnter`, `onLeave`, `onReject` and `dropEffect`. Handle `WU_CAPABILITY_DENIED`, `WU_DRAG_INVALID`, `WU_DRAG_NO_TARGET` and `WU_DRAG_ACCEPT_DENIED`; update business state only when `onDrop` confirms delivery.

Also try [Apps in motion](/labs/interaction/): a React editor, Vue inbox, windows and PiP, typed delivery, transitions and keep-alive. The [scenario guide](/docs/guides/interactive-workspace/) explains how to apply it to your application.