LogoLogo
ExamplesExperimentalCommunityGithub
  • Overview
  • Introduction
    • Installation
    • Quick start
  • API Documentation
    • DndContext
      • Collision detection algorithms
      • useDndContext
      • useDndMonitor
    • Droppable
      • useDroppable
    • Draggable
      • useDraggable
      • Drag Overlay
    • Sensors
      • Pointer
      • Mouse
      • Touch
      • Keyboard
    • Modifiers
  • Presets
    • Sortable
      • Sortable Context
      • useSortable
  • Guides
    • Accessibility
Powered by GitBook
On this page
  • When should I use a drag overlay?
  • Usage
  • Patterns
  • Presentational components
  • Portals
  • Props
  • Children
  • Class name and inline styles
  • Drop animation
  • Modifiers
  • Transition
  • Wrapper element
  • z-index
Edit on Git
  1. API Documentation
  2. Draggable

Drag Overlay

Last updated 3 years ago

The <DragOverlay> component provides a way to render a draggable overlay that is removed from the normal document flow and is positioned relative to the viewport.

When should I use a drag overlay?

  • If you'd like to show a preview of where the draggable source will be when dropped, you can update the position of the draggable source while dragging without affecting the drag overlay.

  • If your item needs to move from one container to another while dragging, we strongly recommend you use the <DragOverlay> component so the draggable item can unmount from its original container while dragging and mount back into a different container without affecting the drag overlay.

  • If your draggable item is within a scrollable container, we also recommend you use a <DragOverlay>, otherwise you'll need to set the draggable element to position: fixed yourself so the item isn't restricted to the overflow and stacking context of its scroll container, and can move without being affected by the scroll position of its container.

  • If your useDraggable items are within a virtualized list, you will absolutely want to use a drag overlay, since the original drag source can unmount while dragging as the virtualized container is scrolled.

  • If you want smooth drop animations without the effort of building them yourself.

Usage

You may render any valid JSX within the children of the <DragOverlay>.

The <DragOverlay> component should remain mounted at all times so that it can perform the drop animation. If you conditionally render the <DragOverlay> component, drop animations will not work.

Instead, you should conditionally render the children passed to the <DragOverlay>:

import React, {useState} from 'react';
import {DndContext, DragOverlay} from '@dnd-kit/core';

import {Draggable} from './Draggable';

/* The implementation details of <Item> and <ScrollableList> are not
 * relevant for this example and are therefore omitted. */

function App() {
  const [items] = useState(['1', '2', '3', '4', '5']);
  const [activeId, setActiveId] = useState(null);
  
  return (
    <DndContext onDragStart={handleDragStart} onDragEnd={handleDragEnd}>
      <ScrollableList>
        {items.map(id =>
          <Draggable key={id} id={id}>
            <Item value={`Item ${id}`} />
          </Draggable>
        )}
      </ScrollableList>
      
      <DragOverlay>
        {activeId ? (
          <Item value={`Item ${activeId}`} /> 
        ): null}
      </DragOverlay>
    </DndContext>
  );
  
  function handleDragStart(event) {
    setActiveId(event.active.id);
  }
  
  function handleDragEnd() {
    setActiveId(null);
  }
}
import React from 'react';
import {useDraggable} from '@dnd-kit/core';

function Draggable(props) {
  const {attributes, listeners, setNodeRef} = useDraggable({
    id: props.id,
  });
  
  return (
    <li ref={setNodeRef} {...listeners} {...attributes}>
      {props.children}
    </li>
  );
}

Patterns

Presentational components

Using this pattern, create a presentational version of your component that you intend on rendering within the drag overlay, and another version that is draggable and renders the presentational component.

Wrapper nodes

As you may have noticed from the example above, we can create small abstract components that render a wrapper node and make any children rendered within draggable:

import React from 'react';
import {useDraggable} from '@dnd-kit/core';

function Draggable(props) {
  const Element = props.element || 'div';
  const {attributes, listeners, setNodeRef} = useDraggable({
    id: props.id,
  });
  
  return (
    <Element ref={setNodeRef} {...listeners} {...attributes}>
      {props.children}
    </Element>
  );
}

Using this pattern, we can then render our presentational components within <Draggable> and within <DragOverlay>:

import React, {useState} from 'react';
import {DndContext, DragOverlay} from '@dnd-kit/core';

import {Draggable} from './Draggable';

/* The implementation details of <Item> is not
 * relevant for this example and therefore omitted. */

function App() {
  const [isDragging, setIsDragging] = useState(false);
  
  return (
    <DndContext onDragStart={handleDragStart} onDragEnd={handleDragEnd}>
      <Draggable id="my-draggable-element">
        <Item />
      </Draggable>
      
      <DragOverlay>
        {isDragging ? (
          <Item />
        ): null}
      </DragOverlay>
    </DndContext>
  );
  
  function handleDragStart() {
    setIsDragging(true);
  }
  
  function handleDragEnd() {
    setIsDragging(false);
  }
}

Ref forwarding

import React, {forwardRef} from 'react';

const Item = forwardRef(({children, ...props}, ref) => {
  return (
    <li {...props} ref={ref}>{children}</li>
  )
});

This way, you can create two versions of your component, one that is presentational, and one that is draggable and renders the presentational component without the need for additional wrapper elements:

import React from 'react';
import {useDraggable} from '@dnd-kit/core';

function DraggableItem(props) {
  const {attributes, listeners, setNodeRef} = useDraggable({
    id: props.id,
  });
  
  return (
    <Item ref={setNodeRef} {...attributes} {...listeners}>
      {value}
    </Item>
  )
});

Portals

The drag overlay is not rendered in a portal by default. Rather, it is rendered in the container where it is rendered.

import React, {useState} from 'react';
import {createPortal} from 'react-dom';
import {DndContext, DragOverlay} from '@dnd-kit/core';

function App() {
  return (
    <DndContext>
      {createPortal(
        <DragOverlay>{/* ... */}</DragOverlay>,
        document.body,
      )}
    </DndContext>
  );
}

Props

{
  adjustScale?: boolean;
  children?: React.ReactNode;
  className?: string;
  dropAnimation?: DropAnimation | null;
  style?: React.CSSProperties;
  transition?: string | TransitionGetter;
  modifiers?: Modifiers;
  wrapperElement?: keyof JSX.IntrinsicElements;
  zIndex?: number;
}

Children

You may render any valid JSX within the children of the <DragOverlay>. However, make sure that the components rendered within the drag overlay do not use the useDraggable hook.

Prefer conditionally rendering the children of <DragOverlay> rather than conditionally rendering <DragOverlay>, otherwise drop animations will not work.

Class name and inline styles

<DragOverlay
  className="my-drag-overlay"
  style={{
    width: 500,
  }}
>
  {/* ... */}
</DragOverlay>

Drop animation

Use the dropAnimation prop to configure the drop animation.

interface DropAnimation {
  duration: number;
  easing: string;
}
<DragOverlay dropAnimation={{
  duration: 500,
  easing: 'cubic-bezier(0.18, 0.67, 0.6, 1.22)',
}}>
  {/* ... */}
</DragOverlay>

To disable drop animations, set the dropAnimation prop to null.

<DragOverlay dropAnimation={null}>
  {/* ... */}
</DragOverlay>

The <DragOverlay> component should remain mounted at all times so that it can perform the drop animation. If you conditionally render the <DragOverlay> component, drop animations will not work.

Modifiers

For example, you can use modifiers to restrict the movement of the <DragOverlay> to the bounds of the window:

import {DndContext, DragOverlay} from '@dnd-kit';
import {
  restrictToWindowEdges,
} from '@dnd-kit/modifiers';

function App() {
  return (
    <DndContext>
      {/* ... */}
      <DragOverlay modifiers={[restrictToWindowEdges]}>
        {/* ... */}
      </DragOverlay>
    </DndContext>
  )
}

Transition

function defaultTransition(activatorEvent) {
  const isKeyboardActivator = activatorEvent instanceof KeyboardEvent;

  return isKeyboardActivator ? 'transform 250ms ease' : undefined;
};

Wrapper element

By default, the <DragOverlay> component renders your elements within a div element. If your draggable elements are list items, you'll want to update the <DragOverlay> component to render a ul wrapper instead, since wrapping a li item without a parent ul is invalid HTML:

<DragOverlay wrapperElement="ul">
  {/* ... */}
</DragOverlay>

z-index

Depending on your use-case, you may want to use a drag overlay rather than transforming the original draggable source element that is connected to the hook:

As a rule of thumb, try to render the <DragOverlay> outside of your draggable components, and follow the to maintain a good separation of concerns.

While this is an optional pattern, we recommend that the components you intend to make draggable be that are decoupled from @dnd-kit.

Use the to connect your presentational components to the useDraggable hook:

If you would like to render the <DragOverlay> in a different container than where it is rendered, import the helper from react-dom:

If you'd like to customize the that the DragOverlay's children are rendered into, use the className and style props:

The duration option should be a number, in milliseconds. The default value is 250 milliseconds. The easing option should be a string that represents a valid . The default easing is ease.

Modifiers let you dynamically modify the movement coordinates that are detected by sensors. They can be used for a wide range of use-cases, which you can learn more about by reading the documentation.

By default, the <DragOverlay> component does not have any transitions, unless activated by the . Use the transition prop to create a function that returns the transition based on the . The default implementation is:

The zIndex prop sets the of the drag overlay. The default value is 999 for compatibility reasons, but we highly recommend you use a lower value.

useDraggable
presentational component pattern
presentational components
ref forwarding pattern
createPortal
wrapper element
CSS easing function
Modifiers
Keyboard sensor
activator event
z-order