or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

tessl/npm-react-easy-crop

A React component to crop images/videos with easy interactions

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/react-easy-crop@5.5.x

To install, run

npx @tessl/cli install tessl/npm-react-easy-crop@5.5.0

0

# React Easy Crop

1

2

React Easy Crop is a React component library that provides an intuitive interface for cropping images and videos with drag, zoom, and rotate interactions. It supports multiple media formats, offers mobile-friendly touch gestures, and provides crop coordinates in both pixels and percentages.

3

4

## Package Information

5

6

- **Package Name**: react-easy-crop

7

- **Package Type**: npm

8

- **Language**: TypeScript

9

- **Installation**: `npm install react-easy-crop`

10

11

## Core Imports

12

13

```typescript

14

import Cropper from "react-easy-crop";

15

import type { CropperProps, Area, Point, Size, MediaSize, VideoSrc } from "react-easy-crop";

16

```

17

18

For helper functions:

19

20

```typescript

21

import {

22

getInitialCropFromCroppedAreaPixels,

23

getInitialCropFromCroppedAreaPercentages

24

} from "react-easy-crop";

25

```

26

27

CommonJS:

28

29

```javascript

30

const Cropper = require("react-easy-crop").default;

31

const { getInitialCropFromCroppedAreaPixels, getInitialCropFromCroppedAreaPercentages } = require("react-easy-crop");

32

```

33

34

## Basic Usage

35

36

```typescript

37

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

38

import Cropper from 'react-easy-crop';

39

import type { Area, Point } from 'react-easy-crop';

40

41

const CropDemo = () => {

42

const [crop, setCrop] = useState<Point>({ x: 0, y: 0 });

43

const [zoom, setZoom] = useState(1);

44

const [rotation, setRotation] = useState(0);

45

const [croppedAreaPixels, setCroppedAreaPixels] = useState<Area | null>(null);

46

47

const onCropComplete = useCallback(

48

(croppedArea: Area, croppedAreaPixels: Area) => {

49

setCroppedAreaPixels(croppedAreaPixels);

50

},

51

[]

52

);

53

54

return (

55

<div style={{ position: 'relative', width: '100%', height: 400 }}>

56

<Cropper

57

image="/path/to/image.jpg"

58

crop={crop}

59

zoom={zoom}

60

rotation={rotation}

61

aspect={4 / 3}

62

onCropChange={setCrop}

63

onZoomChange={setZoom}

64

onRotationChange={setRotation}

65

onCropComplete={onCropComplete}

66

style={{}}

67

classes={{}}

68

mediaProps={{}}

69

cropperProps={{}}

70

/>

71

</div>

72

);

73

};

74

```

75

76

## Capabilities

77

78

### Cropper Component

79

80

The main React component for image and video cropping with interactive controls.

81

82

```typescript { .api }

83

interface CropperProps {

84

/** Current crop position */

85

crop: Point;

86

/** Current zoom level */

87

zoom: number;

88

/** Current rotation in degrees */

89

rotation: number;

90

/** Crop aspect ratio */

91

aspect: number;

92

/** Crop position change callback */

93

onCropChange: (location: Point) => void;

94

95

/** Image URL or base64 string */

96

image?: string;

97

/** Video source(s) */

98

video?: string | VideoSrc[];

99

/** Custom CSS transform */

100

transform?: string;

101

/** Minimum zoom level */

102

minZoom: number;

103

/** Maximum zoom level */

104

maxZoom: number;

105

/** Shape of crop area */

106

cropShape: 'rect' | 'round';

107

/** Fixed crop size */

108

cropSize?: Size;

109

/** Media object fit (default: 'contain') */

110

objectFit?: 'contain' | 'cover' | 'horizontal-cover' | 'vertical-cover';

111

/** Show crop grid overlay */

112

showGrid?: boolean;

113

/** Zoom sensitivity */

114

zoomSpeed: number;

115

/** Enable zoom with mouse wheel */

116

zoomWithScroll?: boolean;

117

/** Round crop area pixel values */

118

roundCropAreaPixels?: boolean;

119

/** Restrict crop position within media bounds */

120

restrictPosition: boolean;

121

/** Keyboard navigation step size */

122

keyboardStep: number;

123

124

/** Zoom level change callback */

125

onZoomChange?: (zoom: number) => void;

126

/** Rotation change callback */

127

onRotationChange?: (rotation: number) => void;

128

/** Crop interaction complete callback */

129

onCropComplete?: (croppedArea: Area, croppedAreaPixels: Area) => void;

130

/** Crop area change callback */

131

onCropAreaChange?: (croppedArea: Area, croppedAreaPixels: Area) => void;

132

/** Crop size change callback */

133

onCropSizeChange?: (cropSize: Size) => void;

134

/** Interaction start callback */

135

onInteractionStart?: () => void;

136

/** Interaction end callback */

137

onInteractionEnd?: () => void;

138

/** Media loaded callback */

139

onMediaLoaded?: (mediaSize: MediaSize) => void;

140

141

/** Custom styles */

142

style: {

143

containerStyle?: React.CSSProperties;

144

mediaStyle?: React.CSSProperties;

145

cropAreaStyle?: React.CSSProperties;

146

};

147

/** Custom CSS classes */

148

classes: {

149

containerClassName?: string;

150

mediaClassName?: string;

151

cropAreaClassName?: string;

152

};

153

154

/** Props passed to media element */

155

mediaProps: React.ImgHTMLAttributes<HTMLElement> | React.VideoHTMLAttributes<HTMLElement>;

156

/** Props passed to cropper div */

157

cropperProps: React.HTMLAttributes<HTMLDivElement>;

158

/** Disable automatic CSS injection */

159

disableAutomaticStylesInjection?: boolean;

160

/** Initial crop area in pixels */

161

initialCroppedAreaPixels?: Area;

162

/** Initial crop area in percentages */

163

initialCroppedAreaPercentages?: Area;

164

/** Touch request handler */

165

onTouchRequest?: (e: React.TouchEvent<HTMLDivElement>) => boolean;

166

/** Wheel request handler */

167

onWheelRequest?: (e: WheelEvent) => boolean;

168

/** Cropper ref callback */

169

setCropperRef?: (ref: React.RefObject<HTMLDivElement>) => void;

170

/** Image ref callback */

171

setImageRef?: (ref: React.RefObject<HTMLImageElement>) => void;

172

/** Video ref callback */

173

setVideoRef?: (ref: React.RefObject<HTMLVideoElement>) => void;

174

/** Media size callback */

175

setMediaSize?: (size: MediaSize) => void;

176

/** Crop size callback */

177

setCropSize?: (size: Size) => void;

178

/** CSP nonce for injected styles */

179

nonce?: string;

180

}

181

182

declare const Cropper: React.ComponentType<CropperProps>;

183

export default Cropper;

184

```

185

186

### Helper Functions

187

188

Functions to compute initial crop settings from predefined cropped areas.

189

190

```typescript { .api }

191

/**

192

* Compute initial crop position and zoom from pixel coordinates

193

* @param croppedAreaPixels - The crop area in pixels

194

* @param mediaSize - The media dimensions

195

* @param rotation - Current rotation in degrees (default: 0)

196

* @param cropSize - The crop area size

197

* @param minZoom - Minimum zoom level

198

* @param maxZoom - Maximum zoom level

199

* @returns Initial crop position and zoom level

200

*/

201

function getInitialCropFromCroppedAreaPixels(

202

croppedAreaPixels: Area,

203

mediaSize: MediaSize,

204

rotation?: number,

205

cropSize: Size,

206

minZoom: number,

207

maxZoom: number

208

): { crop: Point; zoom: number };

209

210

/**

211

* Compute initial crop position and zoom from percentage coordinates

212

* @param croppedAreaPercentages - The crop area in percentages

213

* @param mediaSize - The media dimensions

214

* @param rotation - Current rotation in degrees (required parameter)

215

* @param cropSize - The crop area size

216

* @param minZoom - Minimum zoom level

217

* @param maxZoom - Maximum zoom level

218

* @returns Initial crop position and zoom level

219

*/

220

function getInitialCropFromCroppedAreaPercentages(

221

croppedAreaPercentages: Area,

222

mediaSize: MediaSize,

223

rotation: number,

224

cropSize: Size,

225

minZoom: number,

226

maxZoom: number

227

): { crop: Point; zoom: number };

228

```

229

230

## Types

231

232

```typescript { .api }

233

/** Size dimensions */

234

interface Size {

235

width: number;

236

height: number;

237

}

238

239

/** Media size with natural dimensions */

240

interface MediaSize {

241

width: number;

242

height: number;

243

naturalWidth: number;

244

naturalHeight: number;

245

}

246

247

/** Point coordinates */

248

interface Point {

249

x: number;

250

y: number;

251

}

252

253

/** Rectangular area definition */

254

interface Area {

255

width: number;

256

height: number;

257

x: number;

258

y: number;

259

}

260

261

/** Video source configuration */

262

interface VideoSrc {

263

src: string;

264

type?: string;

265

}

266

```

267

268

## Usage Examples

269

270

### Image Cropping with Custom Aspect Ratio

271

272

```typescript

273

import React, { useState } from 'react';

274

import Cropper from 'react-easy-crop';

275

import type { Area, Point } from 'react-easy-crop';

276

277

const ImageCropper = ({ imageSrc }: { imageSrc: string }) => {

278

const [crop, setCrop] = useState<Point>({ x: 0, y: 0 });

279

const [zoom, setZoom] = useState(1);

280

const [croppedArea, setCroppedArea] = useState<Area | null>(null);

281

282

return (

283

<div style={{ position: 'relative', width: '100%', height: 400 }}>

284

<Cropper

285

image={imageSrc}

286

crop={crop}

287

zoom={zoom}

288

aspect={16 / 9}

289

onCropChange={setCrop}

290

onZoomChange={setZoom}

291

onCropComplete={(_, croppedAreaPixels) => setCroppedArea(croppedAreaPixels)}

292

showGrid={true}

293

cropShape="rect"

294

style={{}}

295

classes={{}}

296

mediaProps={{}}

297

cropperProps={{}}

298

/>

299

</div>

300

);

301

};

302

```

303

304

### Video Cropping with Multiple Sources

305

306

```typescript

307

import React, { useState } from 'react';

308

import Cropper from 'react-easy-crop';

309

import type { VideoSrc, Point } from 'react-easy-crop';

310

311

const VideoCropper = () => {

312

const [crop, setCrop] = useState<Point>({ x: 0, y: 0 });

313

const [zoom, setZoom] = useState(1);

314

315

const videoSources: VideoSrc[] = [

316

{ src: '/video.mp4', type: 'video/mp4' },

317

{ src: '/video.webm', type: 'video/webm' }

318

];

319

320

return (

321

<div style={{ position: 'relative', width: '100%', height: 400 }}>

322

<Cropper

323

video={videoSources}

324

crop={crop}

325

zoom={zoom}

326

aspect={1}

327

onCropChange={setCrop}

328

onZoomChange={setZoom}

329

cropShape="round"

330

showGrid={false}

331

style={{}}

332

classes={{}}

333

mediaProps={{}}

334

cropperProps={{}}

335

/>

336

</div>

337

);

338

};

339

```

340

341

### Circular Crop with Custom Styling

342

343

```typescript

344

import React, { useState } from 'react';

345

import Cropper from 'react-easy-crop';

346

import type { Point } from 'react-easy-crop';

347

348

const CircularCropper = ({ imageSrc }: { imageSrc: string }) => {

349

const [crop, setCrop] = useState<Point>({ x: 0, y: 0 });

350

const [zoom, setZoom] = useState(1);

351

352

return (

353

<div style={{ position: 'relative', width: '100%', height: 400 }}>

354

<Cropper

355

image={imageSrc}

356

crop={crop}

357

zoom={zoom}

358

aspect={1}

359

cropShape="round"

360

onCropChange={setCrop}

361

onZoomChange={setZoom}

362

showGrid={false}

363

style={{

364

containerStyle: {

365

backgroundColor: '#333'

366

},

367

cropAreaStyle: {

368

border: '2px solid #fff'

369

}

370

}}

371

classes={{

372

containerClassName: 'custom-cropper-container'

373

}}

374

mediaProps={{}}

375

cropperProps={{}}

376

/>

377

</div>

378

);

379

};

380

```

381

382

### Using Initial Crop from Saved Data

383

384

```typescript

385

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

386

import Cropper, { getInitialCropFromCroppedAreaPixels } from 'react-easy-crop';

387

import type { Area, Point, MediaSize } from 'react-easy-crop';

388

389

const CropperWithInitialCrop = ({ imageSrc, savedCropPixels }: {

390

imageSrc: string;

391

savedCropPixels: Area;

392

}) => {

393

const [crop, setCrop] = useState<Point>({ x: 0, y: 0 });

394

const [zoom, setZoom] = useState(1);

395

const [mediaSize, setMediaSize] = useState<MediaSize | null>(null);

396

397

useEffect(() => {

398

if (mediaSize && savedCropPixels) {

399

const { crop: initialCrop, zoom: initialZoom } = getInitialCropFromCroppedAreaPixels(

400

savedCropPixels,

401

mediaSize,

402

0, // rotation

403

{ width: 300, height: 200 }, // cropSize

404

1, // minZoom

405

3 // maxZoom

406

);

407

setCrop(initialCrop);

408

setZoom(initialZoom);

409

}

410

}, [mediaSize, savedCropPixels]);

411

412

return (

413

<div style={{ position: 'relative', width: '100%', height: 400 }}>

414

<Cropper

415

image={imageSrc}

416

crop={crop}

417

zoom={zoom}

418

aspect={3 / 2}

419

onCropChange={setCrop}

420

onZoomChange={setZoom}

421

onMediaLoaded={setMediaSize}

422

cropSize={{ width: 300, height: 200 }}

423

style={{}}

424

classes={{}}

425

mediaProps={{}}

426

cropperProps={{}}

427

/>

428

</div>

429

);

430

};

431

```