Skip to contents

useDragDropManager

An imperative API for drag and drop.

The useDragDropManager hook returns the page-wide imperative API. It has four registration methods, registerDraggable, registerDropTarget, registerAutoScroller, and registerMonitor. It also provides startKeyboardDrag and cancelDrag. The React components and hooks use the same registration methods internally.

Every call controls the same manager. Calling the hook in two boards does not isolate them, and cancelDrag() ends whichever drag is active on the page. Use distinct kinds and target accept declarations to keep independent features from interacting.

Use it to register an existing element, integrate a non-React widget, or keep registrations in one parent component. The shape sorter above registers its pieces, cutouts, and monitor through one manager. It does not render Draggable.Root, DropTarget.Root, or useDragMonitor.

Call the hook at the top of your component:

Get the manager

registerDraggable, registerDropTarget, and registerAutoScroller take the target element and a getter for its parameters; registerMonitor takes only a getter, since a monitor observes every drag rather than an element. All four return a cleanup that unregisters. Register from an effect and return the cleanup:

Register from an effect

The methods are reference-stable, so they are safe to list as effect dependencies.

When each parameter is read

Base UI reads parameters from the getter at different times:

  • Every dispatch. Event callbacks such as onDragStart, onDrag, and onDrop, and conditions such as canDrop, canScroll, and allowedAxis, are read from the getter each time. Base UI does not make the getter’s closure reactive. Re-register from an effect when its dependencies change, or read mutable refs from the getter when the registration must stay mounted.
  • Once at pickup. Base UI reads kind, payload, label, and preview settings when the drag starts. Changes during the drag apply to the next drag.
  • At registration and the next interaction. Base UI applies gesture styles, aria-roledescription, aria-describedby, and dragHandle when the element registers. It reads them again on the next pointerdown or focusin. Drag behavior, including disabled, keyboardActivation, and dragHandle, is always checked at pickup. Re-register the element to update the idle DOM attributes immediately.

Base UI evaluates a monitor’s accept once when it joins a drag. A monitor whose accept excludes a drag ignores it until it ends. A monitor registered during a drag is matched against the drag already in progress.

Base UI reads the locale and nearest Draggable.PreviewProvider where useDragDropManager is called. Put those providers above the component that calls the hook, regardless of where the registered elements render.

Draggables

Register a drag source with registerDraggable. It accepts the Draggable.Root options, including kind, payload or getPayload, pointerActivation, label, disabled, and the drag event callbacks. It also accepts dragHandle and dragPreview. dragHandle can be an element, ref, or function that restricts pickup to a handle. Unlike Draggable.Root, registerDraggable does not manage tabIndex. Make the element focusable to support keyboard dragging.

Register a drag source

Drag preview

With no preview part to nest, an imperative source uses the same sanitized clone by default. It preserves classes and live element state but rewrites IDs to keep the document unique. Pass dragPreview only to configure or replace it:

A cloned preview for a registered source

offset, modifiers, disabled, and container work as they do on the preview parts. Instead of children, pass a render function for the content. It resolves once at drag start and receives the drag source:

A custom preview for a registered source

A render needs a Draggable.PreviewProvider in the tree, like a Draggable.Preview does, and throws without one. A source that uses the default clone needs no provider.

Drop targets

Register a drop target with registerDropTarget. Its parameters are the props of DropTarget.Root without the element and without trackDragOver (drag-over tracking is a React-layer concept): accept, onDragEnter, onDragLeave, onDrop, and the rest.

TypeScript infers the source payload from accept, but cannot also infer the target’s own payload through the getter. Specify both type arguments, as in registerDropTarget<typeof card, SlotData>, when the target sets payload and reads it as self.payload.

Register a drop target

Auto-scroll

registerAutoScroller enables automatic scrolling and configures one element. If a DragAutoScroll.Provider is already mounted, the registration only changes that element’s behavior. It accepts the same parameters as DragAutoScroll.Root. Use allowedAxis to limit the axes, canScroll to disable scrolling for a drag, maxSpeed to set the speed, and applyScroll to implement custom scrolling. For example, a transformed canvas has no scroll offsets for Base UI to update and often already has a viewport ref.

A canvas that pans itself

Register document.documentElement to customize or disable page auto-scroll.

A page that never scrolls itself

With a provider mounted, Base UI detects a container that appears after data loads or inside a third-party widget when a drag reaches it. Register the container only if you need to change its behavior.

A container that appears later

Monitor drags

Observe every drag with registerMonitor, like useDragMonitor. It takes only a getter:

Register a monitor

Starting a keyboard drag

startKeyboardDrag starts a drag as if the user pressed Space. It focuses the source or handle and returns whether the drag started. Pass the registered element or one of its descendants. The arrow keys move the drag, Space or Enter drops it, and Escape cancels it. Announcements and focus restoration work normally.

Use it with keyboardActivation="manual" when the element needs Space for another action. For example, a “Reorder” menu item can start the drag after Space opens the menu.

Starting from a menu item

It returns false if another drag is active, the draggable is disabled, keyboard activation is off, or onBeforeDragStart cancels. It also returns false for null or a detached element. This handles a source that unmounts before a deferred menu-close callback runs. Passing a mounted element outside a registered draggable throws an error.

Cancelling a drag

cancelDrag ends the active drag and fires onDragEnd with canceled: true and the reason 'imperative-action'. For a keyboard drag, it also restores focus and announces the cancellation. It does nothing when no drag is active. Use it when a route change, dialog, or deleted record invalidates the drag.

Cancelling programmatically

API reference

Returns the page-wide drag-and-drop manager. It includes the registration methods that Draggable.Root, DropTarget.Root, DragAutoScroll.Root, and useDragMonitor are built on, plus startKeyboardDrag to open a keyboard drag from your own trigger and cancelDrag to end the drag in progress.

Use it to register an existing element, integrate a non-React widget, or keep registrations in one place.

Every call controls the same page-wide manager. Base UI reads the locale and nearest Draggable.PreviewProvider at the hook’s call site. Put both providers above the component that calls useDragDropManager, even when the registered elements render elsewhere.

Return value

UseDragDropManagerReturnValue

registerDraggablefunction
Description

Registers a drag source and returns a cleanup that unregisters it.

Base UI reads behavior from the getter on every event. It applies gesture styles, aria-roledescription, and aria-describedby when the element registers, then reads them again on the next pointer press or focus event. Re-register the element to update these idle DOM attributes immediately.

Type
registerDropTargetfunction
Description

Registers a drop target, a place a matching drag can be released, and returns a cleanup that unregisters it.

Type
registerAutoScrollerfunction
Description

Registers auto-scroll parameters for an element, and returns a cleanup that unregisters them.

Scroll containers work without registration. Register one to change its behavior. disabled excludes the element, and overflow: hidden or overflow: clip prevents the page from scrolling. For a canvas moved by a CSS transform, use applyScroll to apply the scroll delta yourself.

Type
registerMonitorfunction
Description

Registers a monitor that observes every matching drag, and returns a cleanup that unregisters it.

Type
cancelDragfunction
Description

Cancels the drag in progress, if any. Fires onDragEnd with canceled: true and, for a keyboard drag, restores focus and announces the cancellation.

Type
startKeyboardDragfunction
Description

Starts a keyboard drag on a registered draggable as if the user pressed Space, and returns whether it started. Arrow keys move the drag, Space or Enter drops it, and Escape cancels it.

With keyboardActivation: 'manual', call this method from another control, such as a “Reorder” item in the draggable’s menu.

Pass the registered element or one of its descendants. A null or detached element returns false, which handles a source that unmounts before a deferred menu-close callback runs. The method also returns false if another drag is active, the draggable is disabled, keyboard activation is off, or onBeforeDragStart cancels. A mounted element outside a registered draggable throws an error.

Type

useDragDropManager.ReturnValueHide