A responsive image cropping tool for React with no dependencies.
—
Helper functions for crop manipulation including aspect ratio enforcement, coordinate conversion, positioning utilities, and constraint handling.
Functions for creating and positioning crops with specific constraints and aspect ratios.
/**
* Creates a crop with a fixed aspect ratio
* Adjusts dimensions to maintain the specified aspect ratio
* Function is overloaded to preserve input unit type
* @param crop - Initial crop configuration with unit specified
* @param aspect - Desired aspect ratio (width/height)
* @param containerWidth - Width of the container element
* @param containerHeight - Height of the container element
* @returns Crop with enforced aspect ratio in same unit as input
*/
function makeAspectCrop(
crop: Pick<PercentCrop, 'unit'> & Partial<Omit<PercentCrop, 'unit'>>,
aspect: number,
containerWidth: number,
containerHeight: number
): PercentCrop;
function makeAspectCrop(
crop: Pick<PixelCrop, 'unit'> & Partial<Omit<PixelCrop, 'unit'>>,
aspect: number,
containerWidth: number,
containerHeight: number
): PixelCrop;
/**
* Centers a crop within the container
* Calculates x,y coordinates to center the crop
* Function is overloaded to preserve input unit type
* @param crop - Crop to center (partial, requires unit and dimensions)
* @param containerWidth - Width of the container element
* @param containerHeight - Height of the container element
* @returns Crop centered within container bounds in same unit as input
*/
function centerCrop(
crop: Pick<PercentCrop, 'unit'> & Partial<Omit<PercentCrop, 'unit'>>,
containerWidth: number,
containerHeight: number
): PercentCrop;
function centerCrop(
crop: Pick<PixelCrop, 'unit'> & Partial<Omit<PixelCrop, 'unit'>>,
containerWidth: number,
containerHeight: number
): PixelCrop;Usage Examples:
import { makeAspectCrop, centerCrop } from "react-image-crop";
// Create a 16:9 aspect ratio crop
const aspectCrop = makeAspectCrop(
{ unit: '%', width: 80 }, // Start with 80% width
16 / 9, // 16:9 aspect ratio
1920, // Container width
1080 // Container height
);
// Create a centered square crop
const centeredCrop = centerCrop(
makeAspectCrop({ unit: '%' }, 1, 800, 600), // Square aspect
800, // Container width
600 // Container height
);
// Combine operations for centered aspect crop
const centeredAspectCrop = centerCrop(
makeAspectCrop(
{ unit: '%', width: 60, height: 40 },
4 / 3, // 4:3 aspect ratio
1024, 768
),
1024, 768
);Functions for converting between pixel and percentage coordinate systems.
/**
* Converts crop coordinates to pixel units
* @param crop - Crop to convert (partial)
* @param containerWidth - Width of the container element
* @param containerHeight - Height of the container element
* @returns Crop with pixel coordinates
*/
function convertToPixelCrop(
crop: Partial<Crop>,
containerWidth: number,
containerHeight: number
): PixelCrop;
/**
* Converts crop coordinates to percentage units
* @param crop - Crop to convert (partial)
* @param containerWidth - Width of the container element
* @param containerHeight - Height of the container element
* @returns Crop with percentage coordinates
*/
function convertToPercentCrop(
crop: Partial<Crop>,
containerWidth: number,
containerHeight: number
): PercentCrop;Usage Examples:
import { convertToPixelCrop, convertToPercentCrop } from "react-image-crop";
// Convert percentage crop to pixels for precise calculations
const percentCrop = { unit: '%', x: 25, y: 25, width: 50, height: 50 };
const pixelCrop = convertToPixelCrop(percentCrop, 800, 600);
// Result: { unit: 'px', x: 200, y: 150, width: 400, height: 300 }
// Convert pixel crop to percentage for responsive layouts
const pixelCropInput = { unit: 'px', x: 100, y: 75, width: 200, height: 150 };
const percentCropOutput = convertToPercentCrop(pixelCropInput, 800, 600);
// Result: { unit: '%', x: 12.5, y: 12.5, width: 25, height: 25 }
// Handle crops with missing properties (uses defaults)
const partialCrop = { unit: 'px', width: 100, height: 100 };
const fullPixelCrop = convertToPixelCrop(partialCrop, 800, 600);
// Result: { unit: 'px', x: 0, y: 0, width: 100, height: 100 }Functions for constraining crops within bounds and handling size limitations.
/**
* Constrains a crop within container bounds and size limits
* Handles aspect ratio preservation and min/max constraints
* @param pixelCrop - Crop in pixel coordinates
* @param aspect - Aspect ratio to maintain (0 for free-form)
* @param ord - Drag handle ordinate being used
* @param containerWidth - Width of the container element
* @param containerHeight - Height of the container element
* @param minWidth - Minimum crop width in pixels (default: 0)
* @param minHeight - Minimum crop height in pixels (default: 0)
* @param maxWidth - Maximum crop width in pixels (default: containerWidth)
* @param maxHeight - Maximum crop height in pixels (default: containerHeight)
* @returns Constrained crop within all specified bounds
*/
function containCrop(
pixelCrop: PixelCrop,
aspect: number,
ord: Ords,
containerWidth: number,
containerHeight: number,
minWidth?: number,
minHeight?: number,
maxWidth?: number,
maxHeight?: number
): PixelCrop;
/**
* Nudges (adjusts) crop position/size based on keyboard input
* Used for keyboard accessibility and fine-tuning
* @param pixelCrop - Current crop in pixel coordinates
* @param key - Keyboard key pressed ('ArrowLeft', 'ArrowRight', etc.)
* @param offset - Amount to nudge in pixels
* @param ord - Drag handle ordinate being manipulated
* @returns Adjusted crop after applying nudge operation
*/
function nudgeCrop(
pixelCrop: PixelCrop,
key: string,
offset: number,
ord: Ords
): PixelCrop;Usage Examples:
import { containCrop, nudgeCrop } from "react-image-crop";
// Constrain crop within bounds with size limits
const unconstrainedCrop = { unit: 'px', x: -10, y: -5, width: 900, height: 700 };
const constrainedCrop = containCrop(
unconstrainedCrop,
16 / 9, // Maintain 16:9 aspect ratio
'se', // Southeast drag handle
800, 600, // Container size
100, 50, // Min width/height
600, 400 // Max width/height
);
// Keyboard nudging for fine adjustments
const currentCrop = { unit: 'px', x: 100, y: 100, width: 200, height: 150 };
const nudgedCrop = nudgeCrop(
currentCrop,
'ArrowRight', // Move right
10, // 10 pixels
'se' // From southeast handle
);
// Handle different keyboard modifiers
const smallNudge = nudgeCrop(currentCrop, 'ArrowUp', 1, 'n'); // 1px up
const mediumNudge = nudgeCrop(currentCrop, 'ArrowUp', 10, 'n'); // 10px up (Shift)
const largeNudge = nudgeCrop(currentCrop, 'ArrowUp', 100, 'n'); // 100px up (Ctrl/Cmd)Core utility functions for common operations and value manipulation.
/**
* Default crop object with zero dimensions in pixel units
* Useful as a starting point for new crops
*/
const defaultCrop: PixelCrop;
/**
* Clamps a number between minimum and maximum values
* @param num - Number to clamp
* @param min - Minimum allowed value
* @param max - Maximum allowed value
* @returns Number clamped within bounds
*/
function clamp(num: number, min: number, max: number): number;
/**
* Conditional class name utility
* Filters out falsy values and joins remaining strings
* @param args - Array of class names (strings) or falsy values
* @returns Space-separated string of valid class names
*/
function cls(...args: unknown[]): string;
/**
* Compares two crop objects for equality
* Handles partial crop objects safely
* @param cropA - First crop (partial)
* @param cropB - Second crop (partial)
* @returns True if crops have identical properties
*/
function areCropsEqual(cropA: Partial<Crop>, cropB: Partial<Crop>): boolean;Usage Examples:
import { defaultCrop, clamp, cls, areCropsEqual } from "react-image-crop";
// Initialize new crop with defaults
const newCrop = { ...defaultCrop, width: 100, height: 100 };
// Clamp values within bounds
const clampedValue = clamp(150, 0, 100); // Result: 100
const clampedPosition = clamp(-10, 0, 800); // Result: 0
// Conditional class names
const className = cls(
'crop-container',
isActive && 'active',
isDisabled && 'disabled',
undefined, // Filtered out
'' // Filtered out
);
// Result: "crop-container active" (if isActive=true, isDisabled=false)
// Compare crops for changes
const oldCrop = { unit: 'px', x: 10, y: 10, width: 100, height: 100 };
const newCrop = { unit: 'px', x: 10, y: 10, width: 100, height: 100 };
if (!areCropsEqual(oldCrop, newCrop)) {
console.log('Crop has changed, update preview');
}Common patterns combining multiple utility functions for complex crop operations.
Creating Responsive Aspect Crops:
import { makeAspectCrop, centerCrop, convertToPercentCrop } from "react-image-crop";
function createResponsiveAspectCrop(
aspect: number,
containerWidth: number,
containerHeight: number,
desiredSizePercent: number = 80
) {
// Create aspect crop with percentage coordinates
const aspectCrop = makeAspectCrop(
{ unit: '%', width: desiredSizePercent },
aspect,
containerWidth,
containerHeight
);
// Center the crop
const centeredCrop = centerCrop(aspectCrop, containerWidth, containerHeight);
// Ensure it's in percentage units for responsiveness
return convertToPercentCrop(centeredCrop, containerWidth, containerHeight);
}
// Usage
const responsiveCrop = createResponsiveAspectCrop(16/9, 1920, 1080, 70);Crop Validation and Correction:
import { convertToPixelCrop, containCrop, convertToPercentCrop } from "react-image-crop";
function validateAndCorrectCrop(
crop: Crop,
containerWidth: number,
containerHeight: number,
aspect?: number,
minWidth?: number,
minHeight?: number
): Crop {
// Convert to pixels for validation
const pixelCrop = convertToPixelCrop(crop, containerWidth, containerHeight);
// Apply constraints
const constrainedCrop = containCrop(
pixelCrop,
aspect || 0,
'se', // Default ordinate for general constraint
containerWidth,
containerHeight,
minWidth,
minHeight
);
// Convert back to original unit
return crop.unit === '%'
? convertToPercentCrop(constrainedCrop, containerWidth, containerHeight)
: constrainedCrop;
}Install with Tessl CLI
npx tessl i tessl/npm-react-image-crop