Skip to main content

Overview

Plugins extend the DragDropManager with additional functionality like accessibility, visual feedback, and auto-scrolling. The default preset includes:
  • Accessibility - Screen reader support
  • AutoScroller - Auto-scroll when near edges
  • Cursor - Cursor styling during drag
  • Feedback - Visual drag feedback
  • PreventSelection - Prevent text selection
Additional plugins always included:
  • ScrollListener - Tracks scroll events
  • Scroller - Manages scrolling logic
  • StyleInjector - Injects plugin styles

Accessibility

Provides screen reader announcements and ARIA attributes for drag-and-drop operations.

Options

import { Accessibility } from '@dnd-kit/dom';

const manager = new DragDropManager({
  plugins: [
    Accessibility.configure({
      id: 'my-dnd',
      announcements: {
        dragstart: (event, manager) => `Picked up ${event.source.id}`,
        dragover: (event, manager) => event.target ? `Over ${event.target.id}` : '',
        dragend: (event, manager) => event.target 
          ? `Dropped on ${event.target.id}`
          : 'Drag cancelled'
      },
      screenReaderInstructions: {
        draggable: 'Press space or enter to start dragging. Use arrow keys to move. Press space or enter to drop.'
      },
      debounce: 500
    })
  ]
});
options
AccessibilityOptions

Features

The Accessibility plugin automatically:
  • Adds role="button" to draggable elements (if not already a button)
  • Adds aria-roledescription="draggable" attribute
  • Adds aria-describedby pointing to instructions
  • Sets aria-pressed / aria-grabbed to indicate drag state
  • Sets aria-disabled based on draggable state
  • Ensures elements are focusable with tabindex="0"
  • Creates a live region for screen reader announcements

AutoScroller

Automatically scrolls containers when dragging near their edges.

Options

import { AutoScroller } from '@dnd-kit/dom';

const manager = new DragDropManager({
  plugins: [
    AutoScroller.configure({
      acceleration: 25,
      threshold: 0.2
    })
  ]
});
options
AutoScrollerOptions

Behavior

  • Automatically detects scrollable containers
  • Scrolls when the dragged element is within the threshold zone
  • Scroll speed increases as you get closer to the edge
  • Works with nested scrollable containers
  • Automatically disabled during keyboard dragging

Cursor

Changes the cursor style during drag operations.

Options

import { Cursor } from '@dnd-kit/dom';

const manager = new DragDropManager({
  plugins: [
    Cursor.configure({
      cursor: 'grabbing' // or 'move', 'grab', etc.
    })
  ]
});
options
CursorOptions

Example

// Use 'move' cursor
Cursor.configure({ cursor: 'move' })

// Use custom cursor
Cursor.configure({ cursor: 'url(custom-cursor.png), auto' })

Feedback

Provides visual feedback during drag operations with drag overlays and drop animations.

Options

import { Feedback } from '@dnd-kit/dom';

const manager = new DragDropManager({
  plugins: [
    Feedback.configure({
      feedback: 'default',
      rootElement: document.body,
      dropAnimation: { duration: 250, easing: 'ease' },
      keyboardTransition: { duration: 250, easing: 'cubic-bezier(0.25, 1, 0.5, 1)' }
    })
  ]
});
options
FeedbackOptions

Feedback Types

Default Feedback

feedback: 'default'
  • Original element hidden with placeholder
  • Element follows cursor
  • Smooth drop animation back to final position

Move Feedback

feedback: 'move'
  • Element itself moves (no clone)
  • No placeholder left behind
  • Good for simple reordering

Clone Feedback

feedback: 'clone'
  • Original element stays visible
  • Clone follows cursor
  • Good for copy operations or when source stays visible

No Feedback

feedback: 'none'
  • No visual feedback
  • Useful for custom implementations

Drop Animation

Customize the animation when dropping:
// Simple options
Feedback.configure({
  dropAnimation: {
    duration: 200,
    easing: 'ease-out'
  }
});

// Custom function
Feedback.configure({
  dropAnimation: async ({ element, feedbackElement, translate, moved }) => {
    // Implement custom animation
    element.style.transition = 'transform 0.3s ease';
    element.style.transform = 'scale(0.8)';
    
    await new Promise(resolve => setTimeout(resolve, 300));
    
    element.style.transform = '';
  }
});

// Disable drop animation
Feedback.configure({
  dropAnimation: null
});

Per-Entity Configuration

Feedback can be configured per draggable:
const draggable = new Draggable(
  {
    id: 'item-1',
    element: document.getElementById('item-1'),
    plugins: [
      Feedback.configure({
        feedback: 'clone',
        dropAnimation: { duration: 150 }
      })
    ]
  },
  manager
);

PreventSelection

Prevents text selection during drag operations.

Usage

import { PreventSelection } from '@dnd-kit/dom';

const manager = new DragDropManager({
  plugins: [
    PreventSelection
  ]
});
No configuration options. Automatically:
  • Applies user-select: none during drag
  • Removes any existing text selection
  • Listens for selection changes and clears them

Scroller

Core scrolling logic used by AutoScroller. Generally used internally.

Usage

import { Scroller } from '@dnd-kit/dom';

// Included automatically, but can be configured
const manager = new DragDropManager({
  plugins: [Scroller]
});

ScrollListener

Tracks scroll events for collision detection updates. Always included automatically.

Usage

import { ScrollListener } from '@dnd-kit/dom';

// Included automatically
const manager = new DragDropManager({
  plugins: [ScrollListener]
});

StyleInjector

Injects CSS for plugins into the document. Always included automatically.

Usage

import { StyleInjector } from '@dnd-kit/dom';

// Included automatically
const manager = new DragDropManager({
  plugins: [StyleInjector]
});

Example: Custom Plugin Configuration

import {
  DragDropManager,
  Accessibility,
  AutoScroller,
  Cursor,
  Feedback
} from '@dnd-kit/dom';

const manager = new DragDropManager({
  plugins: [
    // Custom accessibility announcements
    Accessibility.configure({
      announcements: {
        dragstart: (event) => `Started dragging ${event.source.id}`,
        dragover: (event) => {
          if (event.target) {
            return `Over drop zone ${event.target.id}`;
          }
          return 'Not over a drop zone';
        },
        dragend: (event) => {
          if (event.canceled) return 'Drag cancelled';
          if (event.target) return `Dropped on ${event.target.id}`;
          return 'Dropped';
        }
      },
      debounce: 300
    }),
    
    // Faster auto-scroll
    AutoScroller.configure({
      acceleration: 40,
      threshold: { x: 0.15, y: 0.2 }
    }),
    
    // Custom cursor
    Cursor.configure({
      cursor: 'move'
    }),
    
    // Clone feedback with custom drop animation
    Feedback.configure({
      feedback: 'clone',
      dropAnimation: {
        duration: 200,
        easing: 'ease-out'
      },
      keyboardTransition: {
        duration: 200,
        easing: 'ease'
      }
    })
  ]
});

Example: Minimal Setup

import { DragDropManager, Feedback } from '@dnd-kit/dom';

// Only Feedback, no other plugins
const manager = new DragDropManager({
  plugins: [Feedback]
});

Type Definitions

interface AccessibilityOptions {
  id?: string;
  idPrefix?: {
    description?: string;
    announcement?: string;
  };
  announcements?: Announcements;
  screenReaderInstructions?: ScreenReaderInstructions;
  debounce?: number;
}

interface AutoScrollerOptions {
  acceleration?: number;
  threshold?: number | Record<'x' | 'y', number>;
}

interface CursorOptions {
  cursor?: string;
}

interface FeedbackOptions {
  feedback?: 'default' | 'move' | 'clone' | 'none';
  rootElement?: Element | ((source: Draggable) => Element);
  dropAnimation?: DropAnimation | null;
  keyboardTransition?: KeyboardTransition | null;
}

type DropAnimation = DropAnimationOptions | DropAnimationFunction;

interface DropAnimationOptions {
  duration?: number;
  easing?: string;
}

type DropAnimationFunction = (context: {
  source: Draggable;
  element: Element;
  feedbackElement: Element;
  placeholder: Element | null;
  translate: Coordinates;
  moved: boolean;
}) => Promise<void> | void;

interface KeyboardTransition {
  duration?: number;
  easing?: string;
}

Build docs developers (and LLMs) love