JavaScript Image Cropper

A lightweight, powerful JavaScript image cropper and photo editor component built with LemonadeJS. Crop, resize, rotate, and adjust images directly in your web browser with this modern, reactive image editing solution.

The LemonadeJS cropper is based on jSuites image cropper component. For spreadsheet integration, see Jspreadsheet CE Images (free) or Jspreadsheet Pro with advanced Media Integration.

Key Features

  • Image Cropping: Intuitive drag-and-drop interface for precise image cropping
  • Image Rotation: Rotate images with smooth, real-time preview
  • Zoom Control: Fine-grained zoom functionality from 0.1x to 5.45x
  • Image Adjustments: Brightness and contrast controls for professional results
  • Responsive Design: Automatically adapts to mobile and desktop screens
  • Modal Interface: Clean, user-friendly modal dialog for editing
  • Blob Output: Generates cropped images as blobs for easy upload
  • Original Image Preservation: Optionally keep the original image alongside the cropped version
  • TypeScript Support: Full TypeScript definitions included
  • Framework Integration: Works with vanilla JavaScript, React, Vue, and any modern framework

Documentation

Installation

NPM Installation

npm install @lemonadejs/cropper

CDN Installation

<!-- LemonadeJS Core -->
<script src="https://cdn.jsdelivr.net/npm/lemonadejs/dist/lemonade.min.js"></script>

<!-- jSuites Cropper (dependency) -->
<script src="https://cdn.jsdelivr.net/npm/@jsuites/cropper/cropper.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@jsuites/cropper/cropper.min.css" />

<!-- LemonadeJS Cropper Plugin -->
<script src="https://cdn.jsdelivr.net/npm/@lemonadejs/cropper/dist/index.min.js"></script>

Options

Property Type Default Description
width number 300 Width of the crop area in pixels
height number 240 Height of the crop area in pixels
original boolean false Whether to preserve the original image
name string undefined Name attribute for form integration
value ImageData null Initial image data

Methods

Method Description
getValue() Retrieve the current cropped image data and metadata
setValue(data) Set or update the image in the cropper (accepts URL, ImageData, or null)
open() Programmatically open the cropper modal interface
uploadPhoto() Launch the file picker modal to select a new photo
deletePhoto() Remove the current image from the cropper container
setControls(state) Enable or disable the editing controls (zoom, rotate, brightness, contrast)

Properties

Property Type Description
brightness number Current brightness adjustment value (-1 to 1)
contrast number Current contrast adjustment value (-1 to 1)
greyscale number Current greyscale value (0 to 1)
cropperArea HTMLElement Reference to the cropper area DOM element

ImageData Interface

interface ImageData {
    file: string;       // URL or blob URL to the image
    content?: string;   // Base64 or data URL content
    extension?: string; // File extension (e.g., 'jpg', 'png')
    original?: string;  // Original image URL (if preserved)
    guid?: string;
}

Examples

Basic Image Cropper

<!DOCTYPE html>
<html>
<head>
    <script src="https://cdn.jsdelivr.net/npm/lemonadejs/dist/lemonade.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/@jsuites/cropper/cropper.min.js"></script>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@jsuites/cropper/cropper.min.css" />
    <script src="https://cdn.jsdelivr.net/npm/@lemonadejs/cropper/dist/index.min.js"></script>
</head>
<body>
<div id="root"></div>

<script>
    const root = document.getElementById('root');
    const cropper = Cropper(root, {
        width: 300,
        height: 240
    });
</script>
</body>
</html>

Using with LemonadeJS Component

import lemonade from 'lemonadejs';
import Cropper from '@lemonadejs/cropper';

export default function MyApp() {
    const self = this;

    return `<div>
        <h1>Profile Picture Editor</h1>
        <Cropper
            width="400"
            height="300"
            :ref="self.cropper"
            original="true" />
        <button onclick="self.cropper.open()">Edit Photo</button>
    </div>`;
}

React Integration

import React, { useRef, useEffect } from 'react';
import Cropper from '@lemonadejs/cropper';

function PhotoEditor() {
    const cropperRef = useRef(null);
    const containerRef = useRef(null);

    useEffect(() => {
        if (containerRef.current) {
            cropperRef.current = Cropper(containerRef.current, {
                width: 400,
                height: 300,
                original: true
            });
        }

        return () => {
            // Cleanup if needed
        };
    }, []);

    const handleGetImage = () => {
        if (cropperRef.current) {
            const imageData = cropperRef.current.getValue();
            console.log('Image data:', imageData);
        }
    };

    return (
        <div>
            <div ref={containerRef}></div>
            <button onClick={handleGetImage}>Get Image Data</button>
        </div>
    );
}

export default PhotoEditor;

Advanced Configuration

const cropper = Cropper(document.getElementById('root'), {
    width: 500,          // Crop area width
    height: 400,         // Crop area height
    original: true,      // Preserve original image
    name: 'profile_pic'  // Form field name
});

// Set an image programmatically
cropper.setValue({
    file: 'https://example.com/image.jpg'
});

// Get cropped image data
const imageData = cropper.getValue();
console.log(imageData);
// Output: { file: 'blob:...', content: 'data:image/png;base64,...', extension: 'png' }

Profile Picture Upload

const profileCropper = Cropper(document.getElementById('profile-editor'), {
    width: 200,
    height: 200,
    original: true
});

// After user crops the image
async function uploadProfilePicture() {
    const data = profileCropper.getValue();

    if (data && data.content) {
        const formData = new FormData();
        const response = await fetch(data.content);
        const blob = await response.blob();
        formData.append('profile_picture', blob, 'profile.png');

        // Upload to server
        await fetch('/api/upload', {
            method: 'POST',
            body: formData
        });
    }
}

E-commerce Product Image Editor

const productCropper = Cropper(document.getElementById('product-images'), {
    width: 800,
    height: 600,
    original: true,  // Keep original for zoom functionality
    name: 'product_image'
});

// Handle multiple product images
function addProductImage(imageUrl) {
    productCropper.setValue({
        file: imageUrl,
        original: imageUrl
    });
}

Responsive Mobile-Friendly Cropper

// Automatically adjusts for mobile devices
const responsiveCropper = Cropper(document.getElementById('mobile-editor'), {
    width: window.innerWidth < 640 ? window.innerWidth - 40 : 600,
    height: window.innerWidth < 640 ? window.innerWidth - 40 : 450
});

// The cropper automatically adapts its interface for screens < 800px