Modern Image Crop Web Component – VanillaJCrop
It comes with two integration modes: a declarative <jcrop-widget> Web Component and a programmatic headless API.
Both modes handle mouse, touch, and pen input through the Pointer Events API, and the component scopes all its styles inside Shadow DOM to prevent conflicts with your page CSS.
1. Download the package and import it as a local module.
<script type="module">
import JCrop, { JCropWidget } from './src/index.js';
</script> 2. Add the <jcrop-widget> custom element to your HTML with the src attribute pointing to your image. Constraints like ratio and min-width go directly on the element as attributes:
src (string): The URL of the image to crop.ratio (number or fraction string): The locked aspect ratio. Accepts a decimal (1.5) or a fraction string (16/9).min-width (number): The minimum allowed selection width in pixels.min-height (number): The minimum allowed selection height in pixels.max-width (number): The maximum allowed selection width in pixels.max-height (number): The maximum allowed selection height in pixels.disabled (boolean): Disables all pointer and keyboard interaction when present.<jcrop-widget src="portrait.jpg" ratio="4/3" min-width="80"> </jcrop-widget>
<script type="module">
import { JCropWidget } from './src/index.js';
const cropper = document.querySelector('jcrop-widget');
// Fires each time the user finalizes a crop selection
cropper.addEventListener('crop-select', (e) => {
// e.detail returns coordinates in actual image pixels
const { x, y, w, h } = e.detail;
console.log(`Crop: ${w}x${h} starting at (${x}, ${y})`);
});
// Fires continuously as the user drags
cropper.addEventListener('crop-change', (e) => {
console.log('Live selection:', e.detail);
});
// Fires when the crop selection is cleared
cropper.addEventListener('crop-release', () => {
console.log('No active selection');
});
</script> 3. You can also control the widget through its JavaScript API. Grab the element by reference and call methods directly:
const widget = document.querySelector('jcrop-widget');
// Read the current selection as { x, y, w, h, x2, y2 } in image coordinates
console.log(widget.value);
// Set a new selection immediately
widget.setSelection({ x: 40, y: 40, x2: 380, y2: 290 });
// Animate to a new selection; optional callback fires on completion
widget.animateTo({ x: 100, y: 80, x2: 520, y2: 400 }, () => {
console.log('Transition complete');
});
// Clear the active selection
widget.release();
// Destroy the widget and remove all event listeners
widget.destroy(); 4. The headless API is the right choice when you need crop logic on an existing DOM container or inside a custom canvas pipeline. Pass your element and a configuration object to the JCrop constructor. The imageWidth and imageHeight options map display coordinates back to actual image pixels, so read them from the image element rather than hardcoding.
import JCrop from './src/index.js';
// Attach JCrop to a container element
const jcrop = new JCrop(document.getElementById('crop-stage'), {
canvasWidth: 720, // display width of the rendered crop area
canvasHeight: 480, // display height of the rendered crop area
imageWidth: 2160, // actual pixel width of the source image
imageHeight: 1440, // actual pixel height of the source image
ratio: 3 / 2, // lock to a 3:2 aspect ratio
minWidth: 120,
minHeight: 80,
onChange: (coords) => {
// Fires on every drag move during selection
console.log('In progress:', coords);
},
onSelect: (coords) => {
// Fires when the user releases the pointer
console.log('Final selection:', coords);
submitCropToServer(coords);
},
onRelease: () => {
console.log('Selection cleared');
}
});
// Jump the selection to a position immediately
jcrop.setSelect({ x: 60, y: 40, x2: 420, y2: 320 });
// Animate the selection to a new position
jcrop.animateTo({ x: 100, y: 70, x2: 520, y2: 410 });
// Read the current selection in image coordinates
const imageCoords = jcrop.tellSelect();
// Read the current selection in canvas (display) coordinates
const displayCoords = jcrop.tellScaled();
// Update options at runtime — useful for toggling aspect ratio on the fly
jcrop.setOptions({ ratio: 1, minWidth: 150 });
// Clear the selection
jcrop.release();
// Tear down the instance and remove all listeners
jcrop.dispose(); 5. API configuration options:
canvasWidth (number): Display width of the crop area in pixels. Defaults to 800.canvasHeight (number): Display height of the crop area in pixels. Defaults to 600.imageWidth (number): Actual pixel width of the source image. Defaults to 1600.imageHeight (number): Actual pixel height of the source image. Defaults to 1200.ratio (number | null): Locked aspect ratio as a width-to-height number. Pass null for a free selection. Defaults to null.minWidth (number): Minimum selection width in pixels. Defaults to 50.minHeight (number): Minimum selection height in pixels. Defaults to 50.maxWidth (number): Maximum selection width in pixels. Defaults to Infinity.maxHeight (number): Maximum selection height in pixels. Defaults to Infinity.fadeTime (number): Duration of animated transitions in milliseconds. Defaults to 400.handleWidth (number): Width of resize handles in pixels. Defaults to 10.handleHeight (number): Height of resize handles in pixels. Defaults to 10.onChange (function): Callback that fires on every selection change. Receives a coordinates object.onSelect (function): Callback that fires when the selection is finalized. Receives a coordinates object.onRelease (function): Callback that fires when the selection is cleared. Receives no arguments.6. API methods.
// Set the crop selection immediately; accepts { x, y, x2, y2 } in image pixels
jcrop.setSelect({ x: 80, y: 60, x2: 480, y2: 360 });
// Animate the selection to new coordinates
// Optional second argument is a callback fired when the animation ends
jcrop.animateTo({ x: 120, y: 90, x2: 560, y2: 410 }, () => {
console.log('Animation finished');
});
// Return the current selection in image coordinates: { x, y, w, h, x2, y2 }
const imageCoords = jcrop.tellSelect();
// Return the current selection in canvas (display) coordinates
const displayCoords = jcrop.tellScaled();
// Clear the active selection
jcrop.release();
// Check whether an animation is currently running; returns a boolean
const active = jcrop.isAnimating();
// Stop any running animation at its current position
jcrop.cancelAnimation();
// Update one or more options at runtime; changes take effect immediately
jcrop.setOptions({ ratio: 16 / 9, minWidth: 200 });
// Destroy the instance and remove all event listeners from the DOM
jcrop.dispose(); 7. Web component events.
const widget = document.querySelector('jcrop-widget');
// Fires continuously as the user drags; useful for live coordinate previews
// e.detail: { x, y, w, h, x2, y2 } in image coordinates
widget.addEventListener('crop-change', (e) => {
console.log('Dragging:', e.detail);
});
// Fires once when the user releases the pointer and the selection is confirmed
// e.detail: { x, y, w, h, x2, y2 } in image coordinates
widget.addEventListener('crop-select', (e) => {
console.log('Confirmed crop:', e.detail);
});
// Fires when the current selection is cleared programmatically or by the user
widget.addEventListener('crop-release', () => {
console.log('Selection removed');
});
// Fires on errors; most common cause is a failed image load
// e.detail: { error }
widget.addEventListener('crop-error', (e) => {
console.error('Load failure:', e.detail.error);
}); 8. Customize the cropper with the following CSS variables.
jcrop-widget {
/* Translucent shade overlay outside the selection */ --jcrop-shade-color: rgba(0, 0, 0, 0.6);
/* Selection border */ --jcrop-border-color: #ffffff;
--jcrop-border-width: 2px;
--jcrop-border-style: solid;
/* Resize handle appearance */ --jcrop-handle-size: 14px;
--jcrop-handle-color: #ffffff;
--jcrop-handle-border: 2px solid #1a1a1a;
--jcrop-handle-radius: 3px;
} 9. Migrating from JCrop jQuery plugin:
// ---- JCrop (jQuery) ----
$('#photo').Jcrop({
onSelect: function(c) { console.log(c); },
aspectRatio: 1.5
});
api.setSelect([80, 60, 480, 360]); // array format
api.animateTo([120, 90, 560, 410]); // array format
api.tellSelect();
api.release();
api.destroy();
// ---- VanillaJCrop (ES6+) ----
const jcrop = new JCrop(document.getElementById('photo'), {
onSelect: (c) => console.log(c),
ratio: 1.5
});
jcrop.setSelect({ x: 80, y: 60, x2: 480, y2: 360 }); // object format
jcrop.animateTo({ x: 120, y: 90, x2: 560, y2: 410 }); // object format
jcrop.tellSelect();
jcrop.release();
jcrop.dispose(); // renamed from destroy() The post Modern Image Crop Web Component – VanillaJCrop appeared first on CSS Script.
A dangerous malware campaign has been silently targeting cryptocurrency users by hiding inside a fake…
WASHINGTON, D.C. (WOWO) A leading auto industry group is calling for a major shift in…
WASHINGTON, D.C. (WOWO) A leading auto industry group is calling for a major shift in…
WASHINGTON, D.C. (WOWO) A leading auto industry group is calling for a major shift in…
INDIANAPOLIS, IND. (WOWO) Indiana landowners are being advised to monitor trees this spring as eastern…
INDIANAPOLIS, IND. (WOWO) Indiana landowners are being advised to monitor trees this spring as eastern…
This website uses cookies.