React components for adding drag-and-drop functionality to React applications with position management and boundary controls
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
The Draggable component is a stateful React component that wraps an existing element and makes it draggable using CSS transforms. It manages its own position state and provides extensive configuration options for controlling drag behavior, boundaries, and styling.
The main Draggable component that handles position management internally.
/**
* A React component that makes its single child element draggable
* @param props - Draggable configuration properties
*/
function Draggable(props: DraggableProps): React.ReactElement;
interface DraggableProps extends DraggableCoreProps {
// Movement constraints
axis?: 'both' | 'x' | 'y' | 'none';
bounds?: DraggableBounds | string | false;
// Position management
defaultPosition?: ControlPosition;
position?: ControlPosition;
positionOffset?: PositionOffsetControlPosition;
// Styling classes
defaultClassName?: string;
defaultClassNameDragging?: string;
defaultClassNameDragged?: string;
}Usage Examples:
import React from 'react';
import Draggable from 'react-draggable';
// Basic draggable element
function BasicDraggable() {
return (
<Draggable>
<div className="box">Basic draggable</div>
</Draggable>
);
}
// Draggable with axis constraint
function AxisConstrainedDraggable() {
return (
<Draggable axis="x">
<div className="slider">Horizontal only</div>
</Draggable>
);
}
// Controlled draggable
function ControlledDraggable() {
const [position, setPosition] = React.useState({ x: 0, y: 0 });
const handleDrag = (e, data) => {
setPosition({ x: data.x, y: data.y });
};
return (
<Draggable position={position} onDrag={handleDrag}>
<div>Position: {position.x}, {position.y}</div>
</Draggable>
);
}Control element positioning with various options for initial position, controlled positioning, and position offsets.
/**
* Initial position for uncontrolled draggable elements
*/
defaultPosition?: ControlPosition;
/**
* Controlled position - makes the component controlled
* When provided, component position is externally managed
*/
position?: ControlPosition;
/**
* Position offset from the element's natural position
* Supports pixel values or percentage strings
*/
positionOffset?: PositionOffsetControlPosition;
interface ControlPosition {
x: number;
y: number;
}
interface PositionOffsetControlPosition {
x: number | string;
y: number | string;
}Usage Examples:
import React, { useState } from 'react';
import Draggable from 'react-draggable';
// Uncontrolled with initial position
<Draggable defaultPosition={{ x: 100, y: 50 }}>
<div>Starts at (100, 50)</div>
</Draggable>
// Controlled positioning
function ControlledExample() {
const [pos, setPos] = useState({ x: 0, y: 0 });
return (
<Draggable
position={pos}
onDrag={(e, data) => setPos({ x: data.x, y: data.y })}
>
<div>Controlled position</div>
</Draggable>
);
}
// Position offset with percentages
<Draggable positionOffset={{ x: '50%', y: 20 }}>
<div>Offset from natural position</div>
</Draggable>Control which axes the element can move along and define movement boundaries.
/**
* Constrains movement to specific axes
* 'both' - move freely (default)
* 'x' - horizontal movement only
* 'y' - vertical movement only
* 'none' - no movement (useful for touch scrolling)
*/
axis?: 'both' | 'x' | 'y' | 'none';
/**
* Boundaries for draggable movement
* Object - pixel boundaries: { left?: number, top?: number, right?: number, bottom?: number }
* 'parent' - restricted to offsetParent element
* CSS selector string - restricted to first matching element
* false - no boundaries (default)
*/
bounds?: DraggableBounds | string | false;
interface DraggableBounds {
left?: number;
right?: number;
top?: number;
bottom?: number;
}Usage Examples:
// Vertical slider
<Draggable axis="y" bounds={{ top: 0, bottom: 300 }}>
<div className="vertical-slider">Vertical only</div>
</Draggable>
// Bounded to parent element
<div className="container">
<Draggable bounds="parent">
<div>Can't leave parent</div>
</Draggable>
</div>
// Custom boundary selector
<Draggable bounds=".drag-area">
<div>Bounded to .drag-area element</div>
</Draggable>
// Pixel boundaries
<Draggable bounds={{ left: 0, top: 0, right: 500, bottom: 300 }}>
<div>Bounded to specific area</div>
</Draggable>Snap movement to grid positions and scale drag calculations for zoomed interfaces.
/**
* Snap dragging to a grid
* [x, y] - grid cell size in pixels for each axis
*/
grid?: [number, number];
/**
* Scale factor for drag distance calculations
* Useful when the draggable is inside a scaled/zoomed container
*/
scale?: number;Usage Examples:
// Snap to 20px grid
<Draggable grid={[20, 20]}>
<div>Snaps to grid</div>
</Draggable>
// Scale for zoomed interface (50% zoom)
<Draggable scale={0.5}>
<div>Scaled drag calculations</div>
</Draggable>Configure drag handles, cancel zones, and interaction behavior.
/**
* CSS selector for drag handle
* Only elements matching this selector can initiate drag
*/
handle?: string;
/**
* CSS selector for cancel zones
* Elements matching this selector will not trigger drag
*/
cancel?: string;
/**
* Disable all dragging functionality
*/
disabled?: boolean;
/**
* Allow dragging with any mouse button (not just left-click)
*/
allowAnyClick?: boolean;
/**
* Allow normal scrolling on mobile touch devices
* Prevents drag on scroll gestures
*/
allowMobileScroll?: boolean;Usage Examples:
// Drag handle - only the .handle element starts drag
<Draggable handle=".handle">
<div>
<div className="handle">Drag me</div>
<div>Content area - not draggable</div>
</div>
</Draggable>
// Cancel zones - .no-drag elements prevent drag
<Draggable cancel=".no-drag">
<div>
<button className="no-drag">Button (not draggable)</button>
<div>Draggable area</div>
</div>
</Draggable>
// Mobile-friendly with scroll
<Draggable allowMobileScroll>
<div>Touch and drag, or scroll normally</div>
</Draggable>Handle drag lifecycle events with detailed position and delta information.
/**
* Called when dragging starts
* Return false to cancel the drag
*/
onStart?: DraggableEventHandler;
/**
* Called continuously during drag
* Return false to stop the drag
*/
onDrag?: DraggableEventHandler;
/**
* Called when dragging stops
*/
onStop?: DraggableEventHandler;
/**
* Called on mouse down events (before drag start)
*/
onMouseDown?: (e: MouseEvent) => void;
type DraggableEventHandler = (
e: DraggableEvent,
data: DraggableData
) => void | false;
interface DraggableData {
node: HTMLElement; // The dragged DOM element
x: number; // Current x position
y: number; // Current y position
deltaX: number; // Change in x since last event
deltaY: number; // Change in y since last event
lastX: number; // Previous x position
lastY: number; // Previous y position
}Usage Examples:
function EventHandlingDraggable() {
const handleStart = (e, data) => {
console.log('Drag started at:', data.x, data.y);
// Return false to cancel drag
if (data.x < 0) return false;
};
const handleDrag = (e, data) => {
console.log('Dragging:', {
position: [data.x, data.y],
delta: [data.deltaX, data.deltaY]
});
};
const handleStop = (e, data) => {
console.log('Drag stopped at:', data.x, data.y);
};
return (
<Draggable
onStart={handleStart}
onDrag={handleDrag}
onStop={handleStop}
>
<div>Event handling draggable</div>
</Draggable>
);
}Customize CSS classes applied during different drag states.
/**
* Base CSS class applied to the draggable element
* Default: 'react-draggable'
*/
defaultClassName?: string;
/**
* CSS class applied while dragging
* Default: 'react-draggable-dragging'
*/
defaultClassNameDragging?: string;
/**
* CSS class applied after element has been dragged
* Default: 'react-draggable-dragged'
*/
defaultClassNameDragged?: string;Usage Examples:
<Draggable
defaultClassName="my-draggable"
defaultClassNameDragging="my-draggable--dragging"
defaultClassNameDragged="my-draggable--dragged"
>
<div>Custom styled draggable</div>
</Draggable>Advanced configuration for specific use cases and React compatibility.
/**
* Automatically add user-select: none styles during drag
* Prevents text selection while dragging
*/
enableUserSelectHack?: boolean;
/**
* Custom offset parent for position calculations
* Used for calculating relative positions
*/
offsetParent?: HTMLElement;
/**
* React ref for the draggable element
* Recommended for React Strict Mode compatibility (avoids findDOMNode)
*/
nodeRef?: React.RefObject<HTMLElement>;Usage Examples:
import React, { useRef } from 'react';
import Draggable from 'react-draggable';
function AdvancedDraggable() {
const nodeRef = useRef(null);
return (
<Draggable
nodeRef={nodeRef}
enableUserSelectHack={false} // Allow text selection during drag
>
<div ref={nodeRef}>
Advanced draggable with ref
</div>
</Draggable>
);
}Install with Tessl CLI
npx tessl i tessl/npm-react-draggable