or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

draggable-core.mddraggable.mdindex.md

draggable-core.mddocs/

0

# DraggableCore Component

1

2

DraggableCore is a low-level, stateless React component that provides drag events without any position management or visual transforms. It gives complete control over drag behavior to the parent component, making it perfect for custom drag implementations, complex interactions, or when you need full control over positioning logic.

3

4

## Capabilities

5

6

### Core Component

7

8

The stateless draggable component that only provides drag events.

9

10

```typescript { .api }

11

/**

12

* A low-level draggable component with no internal state

13

* Provides drag events but no position management

14

* @param props - DraggableCore configuration properties

15

*/

16

function DraggableCore(props: DraggableCoreProps): React.ReactElement;

17

18

interface DraggableCoreProps {

19

// Interaction controls

20

handle?: string;

21

cancel?: string;

22

disabled?: boolean;

23

allowAnyClick?: boolean;

24

allowMobileScroll?: boolean;

25

26

// Event handlers (required for functionality)

27

onStart?: DraggableEventHandler;

28

onDrag?: DraggableEventHandler;

29

onStop?: DraggableEventHandler;

30

onMouseDown?: (e: MouseEvent) => void;

31

32

// Advanced options

33

enableUserSelectHack?: boolean;

34

offsetParent?: HTMLElement;

35

grid?: [number, number];

36

scale?: number;

37

nodeRef?: React.RefObject<HTMLElement>;

38

39

// Required

40

children: React.ReactNode;

41

}

42

```

43

44

**Usage Examples:**

45

46

```javascript

47

import React, { useState } from 'react';

48

import { DraggableCore } from 'react-draggable';

49

50

// Basic DraggableCore with manual positioning

51

function CustomDraggable() {

52

const [position, setPosition] = useState({ x: 0, y: 0 });

53

const [dragging, setDragging] = useState(false);

54

55

const handleStart = (e, data) => {

56

setDragging(true);

57

};

58

59

const handleDrag = (e, data) => {

60

setPosition({

61

x: position.x + data.deltaX,

62

y: position.y + data.deltaY

63

});

64

};

65

66

const handleStop = (e, data) => {

67

setDragging(false);

68

};

69

70

return (

71

<DraggableCore

72

onStart={handleStart}

73

onDrag={handleDrag}

74

onStop={handleStop}

75

>

76

<div

77

style={{

78

transform: `translate(${position.x}px, ${position.y}px)`,

79

backgroundColor: dragging ? '#ff0000' : '#0000ff',

80

padding: '10px',

81

cursor: dragging ? 'grabbing' : 'grab'

82

}}

83

>

84

Custom draggable with manual positioning

85

</div>

86

</DraggableCore>

87

);

88

}

89

```

90

91

### Event Handling

92

93

DraggableCore relies entirely on event handlers for functionality since it maintains no internal state.

94

95

```typescript { .api }

96

/**

97

* Called when drag starts

98

* Must be provided to handle drag initiation

99

* Return false to cancel the drag

100

*/

101

onStart?: DraggableEventHandler;

102

103

/**

104

* Called continuously during drag movement

105

* Must be provided to handle position updates

106

* Return false to stop the current drag

107

*/

108

onDrag?: DraggableEventHandler;

109

110

/**

111

* Called when drag ends

112

* Handle final positioning and cleanup

113

*/

114

onStop?: DraggableEventHandler;

115

116

/**

117

* Called on mouse down events before drag consideration

118

*/

119

onMouseDown?: (e: MouseEvent) => void;

120

121

type DraggableEventHandler = (

122

e: DraggableEvent,

123

data: DraggableData

124

) => void | false;

125

126

interface DraggableData {

127

node: HTMLElement; // The dragged DOM element

128

x: number; // Absolute x position relative to offset parent

129

y: number; // Absolute y position relative to offset parent

130

deltaX: number; // Change in x since last drag event

131

deltaY: number; // Change in y since last drag event

132

lastX: number; // Previous absolute x position

133

lastY: number; // Previous absolute y position

134

}

135

```

136

137

**Usage Examples:**

138

139

```javascript

140

import React, { useState, useRef } from 'react';

141

import { DraggableCore } from 'react-draggable';

142

143

// Complex drag behavior with momentum

144

function MomentumDraggable() {

145

const [position, setPosition] = useState({ x: 0, y: 0 });

146

const [velocity, setVelocity] = useState({ x: 0, y: 0 });

147

const lastTime = useRef(Date.now());

148

149

const handleDrag = (e, data) => {

150

const now = Date.now();

151

const dt = (now - lastTime.current) / 1000;

152

153

// Calculate velocity

154

const vx = data.deltaX / dt;

155

const vy = data.deltaY / dt;

156

setVelocity({ x: vx, y: vy });

157

158

// Update position

159

setPosition({

160

x: position.x + data.deltaX,

161

y: position.y + data.deltaY

162

});

163

164

lastTime.current = now;

165

};

166

167

const handleStop = (e, data) => {

168

// Apply momentum after drag stops

169

const momentumX = velocity.x * 0.1;

170

const momentumY = velocity.y * 0.1;

171

172

setPosition({

173

x: position.x + momentumX,

174

y: position.y + momentumY

175

});

176

};

177

178

return (

179

<DraggableCore onDrag={handleDrag} onStop={handleStop}>

180

<div

181

style={{

182

transform: `translate(${position.x}px, ${position.y}px)`,

183

transition: velocity.x !== 0 ? 'transform 0.3s ease-out' : 'none'

184

}}

185

>

186

Momentum draggable

187

</div>

188

</DraggableCore>

189

);

190

}

191

```

192

193

### Interaction Controls

194

195

Configure drag handles, cancel zones, and interaction behavior (same as Draggable).

196

197

```typescript { .api }

198

/**

199

* CSS selector for elements that can initiate drag

200

*/

201

handle?: string;

202

203

/**

204

* CSS selector for elements that prevent drag initiation

205

*/

206

cancel?: string;

207

208

/**

209

* Completely disable drag functionality

210

*/

211

disabled?: boolean;

212

213

/**

214

* Allow dragging with any mouse button

215

*/

216

allowAnyClick?: boolean;

217

218

/**

219

* Allow normal mobile scrolling behavior

220

*/

221

allowMobileScroll?: boolean;

222

```

223

224

**Usage Examples:**

225

226

```javascript

227

// DraggableCore with handle and cancel

228

function HandleDraggableCore() {

229

const [position, setPosition] = useState({ x: 0, y: 0 });

230

231

const handleDrag = (e, data) => {

232

setPosition({

233

x: position.x + data.deltaX,

234

y: position.y + data.deltaY

235

});

236

};

237

238

return (

239

<DraggableCore

240

handle=".drag-handle"

241

cancel=".no-drag"

242

onDrag={handleDrag}

243

>

244

<div style={{ transform: `translate(${position.x}px, ${position.y}px)` }}>

245

<div className="drag-handle" style={{ cursor: 'grab' }}>

246

✋ Drag Handle

247

</div>

248

<div>

249

<button className="no-drag">Button (not draggable)</button>

250

<p>Content area</p>

251

</div>

252

</div>

253

</DraggableCore>

254

);

255

}

256

```

257

258

### Grid and Scaling

259

260

Apply grid snapping and scaling to drag calculations.

261

262

```typescript { .api }

263

/**

264

* Snap drag movements to grid positions

265

* [x, y] - grid cell size in pixels

266

*/

267

grid?: [number, number];

268

269

/**

270

* Scale factor for drag distance calculations

271

* Useful for zoomed/scaled containers

272

*/

273

scale?: number;

274

```

275

276

**Usage Examples:**

277

278

```javascript

279

// Grid-snapped DraggableCore

280

function GridDraggableCore() {

281

const [position, setPosition] = useState({ x: 0, y: 0 });

282

283

const handleDrag = (e, data) => {

284

// Note: grid snapping is applied to the data values automatically

285

setPosition({

286

x: data.x, // Already snapped to grid

287

y: data.y // Already snapped to grid

288

});

289

};

290

291

return (

292

<DraggableCore grid={[25, 25]} onDrag={handleDrag}>

293

<div

294

style={{

295

transform: `translate(${position.x}px, ${position.y}px)`,

296

width: '50px',

297

height: '50px',

298

backgroundColor: '#4CAF50'

299

}}

300

>

301

Grid Snap

302

</div>

303

</DraggableCore>

304

);

305

}

306

```

307

308

### Advanced Configuration

309

310

Fine-tune behavior for specific use cases and React compatibility.

311

312

```typescript { .api }

313

/**

314

* Add user-select: none during drag to prevent text selection

315

* Default: true

316

*/

317

enableUserSelectHack?: boolean;

318

319

/**

320

* Custom offset parent for position calculations

321

*/

322

offsetParent?: HTMLElement;

323

324

/**

325

* React ref for the draggable element

326

* Recommended for React Strict Mode compatibility

327

*/

328

nodeRef?: React.RefObject<HTMLElement>;

329

```

330

331

**Usage Examples:**

332

333

```javascript

334

import React, { useRef, useState } from 'react';

335

import { DraggableCore } from 'react-draggable';

336

337

// React Strict Mode compatible DraggableCore

338

function StrictModeDraggableCore() {

339

const nodeRef = useRef(null);

340

const [position, setPosition] = useState({ x: 0, y: 0 });

341

342

const handleDrag = (e, data) => {

343

setPosition({

344

x: position.x + data.deltaX,

345

y: position.y + data.deltaY

346

});

347

};

348

349

return (

350

<DraggableCore nodeRef={nodeRef} onDrag={handleDrag}>

351

<div

352

ref={nodeRef}

353

style={{

354

transform: `translate(${position.x}px, ${position.y}px)`

355

}}

356

>

357

Strict Mode Compatible

358

</div>

359

</DraggableCore>

360

);

361

}

362

```

363

364

### Common Use Cases

365

366

DraggableCore is ideal for scenarios requiring custom drag behavior:

367

368

**Custom Positioning Logic:**

369

370

```javascript

371

// Custom boundary checking

372

function BoundedDraggableCore() {

373

const [position, setPosition] = useState({ x: 100, y: 100 });

374

375

const handleDrag = (e, data) => {

376

// Custom boundary logic

377

const newX = Math.max(0, Math.min(400, position.x + data.deltaX));

378

const newY = Math.max(0, Math.min(300, position.y + data.deltaY));

379

380

setPosition({ x: newX, y: newY });

381

};

382

383

return (

384

<DraggableCore onDrag={handleDrag}>

385

<div style={{ transform: `translate(${position.x}px, ${position.y}px)` }}>

386

Custom bounded

387

</div>

388

</DraggableCore>

389

);

390

}

391

```

392

393

**Multi-element Coordination:**

394

395

```javascript

396

// Dragging multiple elements simultaneously

397

function MultiElementDrag() {

398

const [positions, setPositions] = useState([

399

{ x: 0, y: 0 }, { x: 100, y: 0 }, { x: 200, y: 0 }

400

]);

401

402

const handleDrag = (index) => (e, data) => {

403

setPositions(prev => prev.map((pos, i) =>

404

i === index

405

? { x: pos.x + data.deltaX, y: pos.y + data.deltaY }

406

: { x: pos.x + data.deltaX * 0.5, y: pos.y + data.deltaY * 0.5 } // Follow drag

407

));

408

};

409

410

return (

411

<div>

412

{positions.map((pos, index) => (

413

<DraggableCore key={index} onDrag={handleDrag(index)}>

414

<div

415

style={{

416

transform: `translate(${pos.x}px, ${pos.y}px)`,

417

width: '50px',

418

height: '50px',

419

backgroundColor: index === 0 ? '#ff0000' : '#cccccc'

420

}}

421

>

422

{index === 0 ? 'Leader' : 'Follower'}

423

</div>

424

</DraggableCore>

425

))}

426

</div>

427

);

428

}

429

```