Cropper
<quiet-cropper>
Crops a region of an image with optional aspect ratio locking, min/max sizing, zoom, pan, and a circular preview. Use a cropper to let users select an avatar, thumbnail, or focal area from an uploaded image before saving.
<quiet-cropper id="cropper__overview-image" src="https://images.unsplash.com/photo-1589538923929-76e12402048b?q=80&w=900" alt="Fluffy cat sitting in a field of wildflowers" min-crop-width="10" min-crop-height="10" > <quiet-toolbar slot="toolbar"> <quiet-button data-cropper="zoom-in" appearance="text" icon-label="Zoom in"> <quiet-icon name="zoom-in"></quiet-icon> </quiet-button> <quiet-button data-cropper="zoom-out" appearance="text" icon-label="Zoom out"> <quiet-icon name="zoom-out"></quiet-icon> </quiet-button> <quiet-button data-cropper="rotate-ccw" appearance="text" icon-label="Rotate counterclockwise"> <quiet-icon name="rotate-2"></quiet-icon> </quiet-button> <quiet-button data-cropper="rotate-cw" appearance="text" icon-label="Rotate clockwise"> <quiet-icon name="rotate-clockwise-2"></quiet-icon> </quiet-button> <quiet-button data-cropper="flip-horizontal" appearance="text" icon-label="Flip horizontally"> <quiet-icon name="flip-vertical"></quiet-icon> </quiet-button> <quiet-button data-cropper="flip-vertical" appearance="text" icon-label="Flip vertically"> <quiet-icon name="flip-horizontal"></quiet-icon> </quiet-button> <quiet-button data-cropper="center" appearance="text" icon-label="Center selection"> <quiet-icon name="focus-centered"></quiet-icon> </quiet-button> <quiet-button data-cropper="toggle-guides" appearance="text" toggle="on" icon-label="Toggle guides"> <quiet-icon name="grid-3x3"></quiet-icon> </quiet-button> <quiet-button data-cropper="toggle-snap" appearance="text" toggle="on" icon-label="Toggle snapping"> <quiet-icon name="magnet"></quiet-icon> </quiet-button> </quiet-toolbar> </quiet-cropper>
This component is a primitive for selecting a region of an image. It is not a form control, so it will not
submit a value to a form. Read the crop with getState() or use toBlob() to
upload the result.
Drag the crop box to move it and drag its handles to resize it. Zoom the image with the mouse wheel or a
two-finger pinch, and drag the dimmed area around the crop box to pan a zoomed-in image. The toolbar below
the image is placed in the toolbar slot and wires its buttons up to the cropper with
data attribute invokers — see
Building a toolbar below.
Examples Jump to heading
Providing an image Jump to heading
Use the src attribute to point at the image to crop. Add alt text to describe it.
This is used as the cropper's accessible name.
<quiet-cropper src="/photo.jpg" alt="Profile photo"></quiet-cropper>
Images loaded from a different origin must be served with
CORS
(Access-Control-Allow-Origin). The internal image is loaded with
crossorigin="anonymous" so the canvas can read pixel data when exporting.
Loading and error slots Jump to heading
Provide custom content for the loading and error states.
<quiet-cropper src="/large-photo.jpg" alt="Cover photo"> <span slot="loading">Loading…</span> <span slot="error">The photo failed to load</span> </quiet-cropper>
Getting the cropped coordinates Jump to heading
There are two ways to get the current crop. Call getState() for a one-time snapshot, or listen
for the quiet-crop-end event to be notified each time the user finishes adjusting.
<quiet-cropper id="cropper__events" src="/photo.jpg" alt="Photo"></quiet-cropper> <script> const cropper = document.getElementById('cropper__events'); // One-time read. The returned state includes `crop`, the region in natural pixels resolved through // the current zoom and rotation. const state = cropper.getState(); console.log(state.crop); // { x, y, width, height } // Or be notified whenever the user finishes adjusting. cropper.addEventListener('quiet-crop-end', event => { const { x, y, width, height } = event.detail; console.log(`Crop: ${width}×${height} at (${x}, ${y})`); }); </script>
The event.detail from any crop event also includes a percent object — the same
x, y, width, and height expressed as fractions (0 to 1)
of the image's natural dimensions — plus the current zoom level and the image's
rotation, flipX, and flipY. Use these when you need to re-apply the
crop to a different size of the same image.
For real-time feedback during a drag, listen for quiet-crop-start (drag began) and
quiet-crop-move (selection changed, throttled to animation frames) in addition to
quiet-crop-end. The quiet-crop-change event fires when the user zooms, pans,
rotates, or flips the image.
Crop events fire only in response to user interaction, including [data-cropper] invokers.
Calling setState(), reset(), or the zoom/rotate/flip methods directly updates
the cropper silently. To build a live preview, read getState() once the
quiet-loaded event fires, then update it on quiet-crop-move,
quiet-crop-end, and quiet-crop-change.
Persisting and restoring a crop Jump to heading
For a full snapshot you can save and restore later, call getState(). It returns a serializable
object describing the crop box (as viewport fractions), the image transform (zoom,
offsetX, offsetY, rotation, flipX, flipY),
and the resolved crop region in natural pixels. Because the crop box and pan are stored as
fractions, the same state restores correctly even against a differently sized variant of the image (e.g.
crop on a thumbnail, then apply to the full-resolution original on the server). Restore it with
setState().
<quiet-cropper id="cropper__state" src="/photo.jpg" alt="Photo"></quiet-cropper> <script type="module"> const cropper = document.getElementById('cropper__state'); // Save whenever the user finishes adjusting (covers crop, zoom, pan, rotation, and flip). const save = () => localStorage.setItem('crop', JSON.stringify(cropper.getState())); cropper.addEventListener('quiet-crop-end', save); cropper.addEventListener('quiet-crop-change', save); // Restore a saved state once the image has loaded (even at a different size). cropper.addEventListener('quiet-loaded', () => { const saved = localStorage.getItem('crop'); if (saved) cropper.setState(JSON.parse(saved)); }); </script>
You can also call setState() before the image loads. It will be applied automatically once the
natural dimensions are known.
Showing a live preview Jump to heading
Render the crop to a fixed-size element as the user adjusts it by calling toCanvas() on each
crop and zoom event. Because toCanvas() bakes in the current zoom, pan, rotation, and flip, the
preview always matches what will be exported. Drag, resize, zoom, or pan the cropper below to watch the
avatar update.
<div id="cropper__preview"> <quiet-cropper src="https://images.unsplash.com/photo-1529778873920-4da4926a72c2?q=80&w=900" alt="Tabby kitten sitting on a tiled floor" aspect-ratio="1" round ></quiet-cropper> <figure> <output></output> <figcaption>Preview</figcaption> </figure> </div> <script type="module"> const wrapper = document.getElementById('cropper__preview'); const cropper = wrapper.querySelector('quiet-cropper'); const output = wrapper.querySelector('output'); const size = 150; function updatePreview() { const canvas = cropper.toCanvas({ width: size, height: size }); if (canvas) output.replaceChildren(canvas); } cropper.addEventListener('quiet-loaded', updatePreview); cropper.addEventListener('quiet-crop-move', updatePreview); cropper.addEventListener('quiet-crop-end', updatePreview); cropper.addEventListener('quiet-crop-change', updatePreview); </script> <style> #cropper__preview { display: flex; align-items: flex-start; flex-wrap: wrap; gap: 1.5rem; quiet-cropper { flex: 1 1 16rem; } figure { display: flex; flex-direction: column; align-items: center; gap: 0.5rem; margin: 0; } output { display: block; width: 150px; height: 150px; border-radius: 50%; overflow: hidden; background-color: var(--quiet-neutral-fill-softer); canvas { display: block; width: 100%; height: 100%; } } figcaption { color: var(--quiet-text-muted); font-size: 0.875rem; } } </style>
Setting the initial coverage Jump to heading
Use initial-coverage (0–1) to control how much of the image is selected on load. The selection
is centered. To restore an exact crop that was saved earlier, call setState() (see
Persisting and restoring a crop).
<quiet-cropper src="https://images.unsplash.com/photo-1518791841217-8f162f1e1131?q=80&w=900" alt="Tabby cat lounging on a couch" initial-coverage="0.6" ></quiet-cropper>
Locking the aspect ratio Jump to heading
Use the aspect-ratio attribute to constrain the crop. Accepts a number (1.5), a
ratio ("16/9"), or "1" for square. When set, edge handles are
hidden so the ratio can't be broken.
<quiet-cropper src="https://images.unsplash.com/photo-1514888286974-6c03e2ca1dba?q=80&w=900" alt="Black and white cat resting on a ledge" aspect-ratio="16/9" ></quiet-cropper>
Choosing from preset ratios Jump to heading
The aspect-ratio attribute can be changed at runtime, so you can offer a small set of common
ratios for users to pick from. Setting it to an empty value returns to free-form cropping.
<div id="cropper__ratios"> <quiet-cropper src="https://images.unsplash.com/photo-1574158622682-e40e69881006?q=80&w=900" alt="Tabby cat against a blue sky" aspect-ratio="1" ></quiet-cropper> <quiet-button-group label="Aspect ratio" style="margin-top: 1rem;"> <quiet-button data-ratio="" >Free</quiet-button> <quiet-button data-ratio="1">Square</quiet-button> <quiet-button data-ratio="16/9">16:9</quiet-button> <quiet-button data-ratio="4/3">4:3</quiet-button> </quiet-button-group> </div> <script type="module"> const wrapper = document.getElementById('cropper__ratios'); const cropper = wrapper.querySelector('quiet-cropper'); wrapper.querySelectorAll('quiet-button').forEach(button => { button.addEventListener('click', () => { cropper.aspectRatio = button.dataset.ratio || null; }); }); </script>
Round selection Jump to heading
Add the round attribute for a circular preview. The crop coordinates and exported images remain
rectangular — this is purely a visual treatment, ideal for avatars. To export a circular image, pass
clipToCircle: true to toBlob(), toCanvas(), or
toDataURL().
<quiet-cropper src="https://images.unsplash.com/photo-1752996985167-0b907781bdee?q=80&w=900" alt="Grey cat resting among ferns" aspect-ratio="1" round ></quiet-cropper>
Restricting the crop size Jump to heading
Use min-crop-width, min-crop-height, max-crop-width, and
max-crop-height to bound the selection. All values are in the source image's natural pixels.
<quiet-cropper src="https://images.unsplash.com/photo-1517451330947-7809dead78d5?q=80&w=900" alt="Tabby cat resting in a basket" aspect-ratio="1" min-crop-width="200" min-crop-height="200" max-crop-width="300" max-crop-height="300" ></quiet-cropper>
Exporting the crop Jump to heading
The toBlob(), toCanvas(), and toDataURL() methods produce the cropped
image at any size. Device pixel ratio is not applied — you get exactly the pixels you ask for.
<quiet-cropper id="cropper__export" src="/photo.jpg" alt="Profile photo"></quiet-cropper> <script type="module"> const cropper = document.getElementById('cropper__export'); // A 400×400 JPEG ready for upload. const blob = await cropper.toBlob({ type: 'image/jpeg', quality: 0.85, width: 400, height: 400 }); // A canvas at the crop's natural resolution. const canvas = cropper.toCanvas(); // A data URL, synchronously. const dataUrl = cropper.toDataURL({ width: 200, height: 200 }); </script>
Exporting from a cross-origin image requires the server to send the
Access-Control-Allow-Origin header. The internal image is loaded with
crossorigin="anonymous".
Exporting for high-density displays Jump to heading
Device pixel ratio is not applied automatically, so a 200×200 export is exactly 200×200 pixels. For crisp
results on high-density (retina) displays, pass pixelRatio and display the result at its
logical size.
// Render at native resolution for a sharp avatar. const blob = await cropper.toBlob({ type: 'image/jpeg', quality: 0.85, width: 200, pixelRatio: window.devicePixelRatio || 1 });
Zooming and panning Jump to heading
Zoom the image with the mouse wheel or a two-finger pinch; drag the dimmed area around the crop box to pan a
zoomed-in image. The image always covers the crop box, so there are never transparent gaps. Use
min-zoom and max-zoom to bound the range, and call zoomIn(),
zoomOut(), or setZoom() to control zoom programmatically. Add
without-zoom to disable it entirely.
<div id="cropper__zoom"> <quiet-cropper src="https://images.unsplash.com/photo-1472491235688-bdc81a63246e?q=80&w=900" alt="Blue-eyed cat looking up" aspect-ratio="1" max-zoom="4" ></quiet-cropper> <quiet-button-group label="Zoom" style="margin-top: 1rem;"> <quiet-button data-action="zoomOut">Zoom out</quiet-button> <quiet-button data-action="zoomIn">Zoom in</quiet-button> </quiet-button-group> </div> <script type="module"> const wrapper = document.getElementById('cropper__zoom'); const cropper = wrapper.querySelector('quiet-cropper'); wrapper.querySelectorAll('quiet-button').forEach(button => { button.addEventListener('click', () => cropper[button.dataset.action]()); }); </script>
Building a toolbar Jump to heading
You can build a custom toolbar with
data attribute invokers. Add
data-cropper="action id" to any button, where action is one of the
actions below and id is the target cropper's id. The ID is optional when the
invoker is nested inside the cropper, so the easiest way to build a toolbar is to place your controls in the
cropper's toolbar slot. Buttons will render below the cropper by default.
| Action | Description |
|---|---|
flip-horizontal |
Flips the image horizontally |
flip-vertical |
Flips the image vertically |
rotate-cw |
Rotates the image 90° clockwise |
rotate-ccw |
Rotates the image 90° counterclockwise |
zoom-in |
Zooms in by one step |
zoom-out |
Zooms out by one step |
center |
Centers the crop selection |
reset |
Resets the crop box and image transform |
toggle-snap |
Toggles center snapping while panning |
snap-on |
Enables center snapping while panning |
snap-off |
Disables center snapping while panning |
toggle-grid |
Toggles the rule-of-thirds grid |
grid-on |
Shows the rule-of-thirds grid |
grid-off |
Hides the rule-of-thirds grid |
toggle-crosshair |
Toggles the center crosshair |
crosshair-on |
Shows the center crosshair |
crosshair-off |
Hides the center crosshair |
toggle-guides |
Toggles the grid and crosshair together |
guides-on |
Shows the grid and crosshair |
guides-off |
Hides the grid and crosshair |
Invoker clicks for actions that change the crop or transform dispatch the same
quiet-crop-change and quiet-crop-end events that user interaction does, so live
previews and saved state stay in sync automatically. The snap-*, grid-*,
crosshair-*, and guides-* actions only flip a without-* setting, so
they dispatch no crop event.
<quiet-cropper id="cropper__custom-toolbar-image" src="https://images.unsplash.com/photo-1518791841217-8f162f1e1131?q=80&w=900" alt="Tabby cat lying on a wooden surface" > <quiet-toolbar slot="toolbar"> <quiet-button data-cropper="rotate-ccw" icon-label="Rotate counterclockwise" appearance="text"> <quiet-icon name="rotate"></quiet-icon> </quiet-button> <quiet-button data-cropper="rotate-cw" icon-label="Rotate clockwise" appearance="text"> <quiet-icon name="rotate-clockwise"></quiet-icon> </quiet-button> <quiet-button data-cropper="flip-horizontal" icon-label="Flip horizontally" appearance="text"> <quiet-icon name="flip-vertical"></quiet-icon> </quiet-button> <quiet-button data-cropper="flip-vertical" icon-label="Flip vertically" appearance="text"> <quiet-icon name="flip-horizontal"></quiet-icon> </quiet-button> <quiet-button data-cropper="zoom-in" icon-label="Zoom in" appearance="text"> <quiet-icon name="zoom-in"></quiet-icon> </quiet-button> <quiet-button data-cropper="zoom-out" icon-label="Zoom out" appearance="text"> <quiet-icon name="zoom-out"></quiet-icon> </quiet-button> <quiet-button data-cropper="center" icon-label="Center selection" appearance="text"> <quiet-icon name="focus-centered"></quiet-icon> </quiet-button> <quiet-button data-cropper="toggle-guides" toggle="on" icon-label="Toggle guides" appearance="text"> <quiet-icon name="grid-3x3"></quiet-icon> </quiet-button> <quiet-button data-cropper="toggle-snap" toggle="on" icon-label="Toggle snapping" appearance="text"> <quiet-icon name="magnet"></quiet-icon> </quiet-button> <quiet-button data-cropper="reset" icon-label="Reset" appearance="text"> <quiet-icon name="refresh"></quiet-icon> </quiet-button> </quiet-toolbar> </quiet-cropper>
The same actions are available programmatically via methods such as flipHorizontal(),
flipVertical(), rotateClockwise(), rotateCounterClockwise(),
rotate(), and centerSelection().
Setting the crop programmatically Jump to heading
Call setState() with a cropBox (fractions of the viewport, 0–1) to move the
selection at runtime. Programmatic changes do not dispatch crop events.
<div id="cropper__random"> <quiet-cropper src="https://images.unsplash.com/photo-1514888286974-6c03e2ca1dba?q=80&w=900" alt="Black and white cat resting on a ledge" ></quiet-cropper> <quiet-button style="margin-top: 1rem;">Randomize</quiet-button> </div> <script type="module"> const wrapper = document.getElementById('cropper__random'); const cropper = wrapper.querySelector('quiet-cropper'); const button = wrapper.querySelector('quiet-button'); button.addEventListener('click', () => { // Pick a random size between 30% and 70% of the viewport, then a random in-bounds position. const width = 0.3 + Math.random() * 0.4; const height = 0.3 + Math.random() * 0.4; const x = Math.random() * (1 - width); const y = Math.random() * (1 - height); cropper.setState({ cropBox: { x, y, width, height } }); }); </script>
Resetting Jump to heading
Call reset() to return the selection and the image transform (zoom, pan, rotation, and flip) to
their initial state. The change is animated and does not dispatch crop events.
<div id="cropper__reset"> <quiet-cropper src="https://images.unsplash.com/photo-1518791841217-8f162f1e1131?q=80&w=900" alt="Tabby cat lounging on a couch" aspect-ratio="1" ></quiet-cropper> <quiet-button style="margin-top: 1rem;">Reset</quiet-button> </div> <script type="module"> const wrapper = document.getElementById('cropper__reset'); const cropper = wrapper.querySelector('quiet-cropper'); // Start in an adjusted state — a smaller selection moved to the top-left, with the image zoomed and panned — so // clicking Reset visibly returns everything to its initial state. cropper.addEventListener('quiet-loaded', () => { cropper.setState({ cropBox: { x: 0.08, y: 0.08, width: 0.45, height: 0.45 }, zoom: 1.8, offsetX: 0.12, offsetY: -0.1 }); }); wrapper.querySelector('quiet-button').addEventListener('click', () => cropper.reset()); </script>
Hiding the guides Jump to heading
While composing the crop, two guides appear: the rule-of-thirds grid and a center crosshair. Add
without-grid to hide the grid, without-crosshair to hide the crosshair, or both to
hide them entirely.
<quiet-cropper src="https://images.unsplash.com/photo-1472491235688-bdc81a63246e?q=80&w=900" alt="Blue-eyed cat looking up" aspect-ratio="4/3" without-grid ></quiet-cropper>
Read-only Jump to heading
Add the readonly attribute to show the current selection without drag handles. The outline and
guides remain visible for preview.
<quiet-cropper src="https://images.unsplash.com/photo-1517451330947-7809dead78d5?q=80&w=900" alt="Tabby cat resting in a basket" aspect-ratio="1" readonly ></quiet-cropper>
Disabled Jump to heading
Add the disabled attribute to remove the crop UI entirely. Only the source image is shown.
<quiet-cropper src="https://images.unsplash.com/photo-1671707696618-ca0685b0012e?q=80&w=900" alt="An orange cat smiles up at the camera" disabled ></quiet-cropper>
Keyboard support Jump to heading
Tab to the cropper to focus it, then use the keys below.
| Key | Action |
|---|---|
| ↑ ↓ ← → | Nudges the selection by one pixel |
| Nudges the selection by ten pixels | |
| Resizes from the bottom-right corner | |
| + - | Zooms in and out |
Constrains the selection to a square (no effect when aspect-ratio is set) |
|
|
|
Temporarily disables snapping to the center |
API Jump to heading
Importing Jump to heading
The autoloader is the recommended way to import components but, if you prefer to do it manually, the following code snippets will be helpful.
To manually import <quiet-cropper> from the CDN, use the following code.
import 'https://cdn.quietui.org/v5.3.1/components/cropper/cropper.js';
To manually import <quiet-cropper> from a self-hosted distribution, use the following
code. Remember to replace /path/to/quiet with the appropriate local path.
import '/path/to/quiet/components/cropper/cropper.js';
Slots Jump to heading
Cropper supports the following slots. Learn more about using slots
| Name | Description |
|---|---|
loading
|
Shown while the image is loading. |
error
|
Shown when the image fails to load. |
toolbar
|
A horizontal toolbar shown beneath the cropper. Slot in custom controls, such as buttons with
[data-cropper] invokers.
|
Properties Jump to heading
Cropper has the following properties that can be set with corresponding attributes. In many cases, the attribute's name is the same as the property's name. If an attribute is different, it will be displayed after the property. Learn more about attributes and properties
| Property | Description | Reflects | Type | Default |
|---|---|---|---|---|
src
|
The image URL to crop. Changing this resets the crop region. |
|
string
|
''
|
alt
|
Accessible label describing the image. |
|
string
|
''
|
aspectRatio
aspect-ratio
|
Aspect ratio of the crop region. Accepts "1", "16/9",
4/3, or any positive number. Set to null (or omit) for free-form cropping.
When locked, only the corner handles are shown.
|
|
string |
number |
null
|
null
|
minCropWidth
min-crop-width
|
Minimum crop width in natural pixels. |
|
number
|
128
|
minCropHeight
min-crop-height
|
Minimum crop height in natural pixels. |
|
number
|
128
|
maxCropWidth
max-crop-width
|
Maximum crop width in natural pixels. Defaults to the image width. |
|
number |
null
|
null
|
maxCropHeight
max-crop-height
|
Maximum crop height in natural pixels. Defaults to the image height. |
|
number |
null
|
null
|
initialCoverage
initial-coverage
|
Fraction of the image (0–1) covered by the initial crop when no explicit state is given. The selection is centered. |
|
number
|
0.8
|
zoom
|
The initial zoom level. 1 means the image fills the viewport. Read the current zoom with
getState(). Setting the attribute only applies before the image loads; use
setZoom() afterwards.
|
|
number
|
|
minZoom
min-zoom
|
Minimum zoom level. Clamped to at least 1 so the image always covers the viewport. |
|
number
|
1
|
maxZoom
max-zoom
|
Maximum zoom level. |
|
number
|
5
|
zoomStep
zoom-step
|
The amount to zoom by when using the wheel, keyboard, or zoom methods. |
|
number
|
0.1
|
withoutZoom
without-zoom
|
Disables zooming and panning the image. The crop box can still be moved and resized. |
|
boolean
|
false
|
round
|
Shows the crop selection as a circle. Coordinates and exported images remain rectangular. |
|
boolean
|
false
|
disabled
|
Disables the cropper. No crop UI is rendered — only the image. |
|
boolean
|
false
|
readonly
|
Shows the current crop selection but prevents the user from changing it. |
|
boolean
|
false
|
withoutGrid
without-grid
|
Hides the rule-of-thirds grid inside the crop selection. |
|
boolean
|
false
|
withoutCrosshair
without-crosshair
|
Hides the center crosshair shown while composing the crop selection. |
|
boolean
|
false
|
withoutSnap
without-snap
|
Disables snapping the crop selection and image to the viewport center while panning. |
|
boolean
|
false
|
naturalWidth
|
Natural width of the loaded source image (0 until loaded). |
|
number
|
|
naturalHeight
|
Natural height of the loaded source image (0 until loaded). |
|
number
|
|
loaded
|
Whether the image has loaded successfully. |
|
boolean
|
Methods Jump to heading
Cropper supports the following methods. You can obtain a reference to the element and call them like functions in JavaScript. Learn more about methods
| Name | Description | Arguments |
|---|---|---|
setZoom() |
Sets the zoom level, optionally anchored on a focal point in viewport pixels. Does not dispatch crop events. |
zoom: number, focal:
{ x: number; y: number }
|
zoomIn() |
Zooms the image in by one step, anchored on the crop box center. | |
zoomOut() |
Zooms the image out by one step, anchored on the crop box center. | |
rotate() |
Rotates the image by the given number of degrees (relative). The transition animates the rotation. Does not dispatch crop events. |
degrees: number
|
rotateClockwise() |
Rotates the image 90° clockwise. | |
rotateCounterClockwise() |
Rotates the image 90° counter-clockwise. | |
flipHorizontal() |
Flips the image horizontally. Does not dispatch crop events. | |
flipVertical() |
Flips the image vertically. Does not dispatch crop events. | |
centerSelection() |
Centers the crop selection in the viewport, keeping its size. Animated. Does not dispatch crop events. | |
toCanvas() |
Returns a canvas containing the cropped region. Output is at the requested size (or the crop's
natural size). Device pixel ratio is not applied automatically — pass pixelRatio for
that.
|
options: ToCanvasOptions
|
toBlob() |
Returns the cropped region as a Blob. type defaults to
image/png.
|
options: ToBlobOptions
|
toDataURL() |
Returns the cropped region as a data URL. |
options: ToBlobOptions
|
reset() |
Resets the crop box and image transform to their initial state. Does not dispatch crop events. | |
getState() |
Returns the full serializable state: crop box (viewport fractions), zoom, pan, and resolved natural crop. | |
setState() |
Applies a partial state (crop box fractions, zoom, and/or pan). Useful for restoring a saved crop against a differently sized variant of the same image. Does not dispatch crop events. |
state: CropperStateInit
|
Events Jump to heading
Cropper dispatches the following custom events. You can listen to them the same way was native events. Learn more about custom events
| Name | Description |
|---|---|
quiet-crop-start |
Emitted when the user begins adjusting the crop box. |
quiet-crop-move |
Emitted while the crop box is being adjusted (throttled to animation frames). |
quiet-crop-end |
Emitted when the user finishes adjusting the crop box (and on keyboard commits). |
quiet-crop-change |
Emitted when the image transform changes through zooming, panning, rotating, or flipping (throttled to animation frames during continuous gestures). |
quiet-loaded |
Emitted when the image has loaded successfully. |
quiet-load-error |
Emitted when the image fails to load. |
CSS custom properties Jump to heading
Cropper supports the following CSS custom properties. You can style them like any other CSS property. Learn more about CSS custom properties
| Name | Description | Default |
|---|---|---|
--outline-width |
Width of the crop outline. |
1px
|
--grid-color |
Color of the rule-of-thirds grid. |
rgb(255 255 255 / 0.3)
|
--grid-width |
Width of the rule-of-thirds grid lines. |
1px
|
--snap-color |
Color of the center snap lines. |
#fbbf23
|
--snap-width |
Width of the center snap lines. |
1px
|
--crosshair-color |
Color of the center crosshair. |
white
|
--crosshair-width |
Stroke width of the center crosshair. |
1px
|
--crosshair-size |
Overall length/height of the center crosshair. |
14px
|
--handle-color |
Fill color of the drag handles. |
white
|
--handle-size |
Length of each corner bracket leg and each edge bar. |
24px
|
--handle-thickness |
Stroke thickness of the corner brackets and edge bars. |
3px
|
CSS parts Jump to heading
Cropper exposes internal elements that can be styled with CSS using the selectors shown below. Learn more about CSS parts
| Name | Description | CSS selector |
|---|---|---|
viewport |
The container that clips the image and holds the crop UI. |
::part(viewport)
|
image |
The internal <img> element. |
::part(image)
|
overlay |
The dimmed region surrounding the crop selection. |
::part(overlay)
|
crop-box |
The interactive crop selection container. |
::part(crop-box)
|
outline |
The border drawn around the crop selection. |
::part(outline)
|
grid |
The rule-of-thirds grid container. |
::part(grid)
|
snap-line |
Both center snap lines shown while panning. |
::part(snap-line)
|
snap-line-x |
The vertical snap line shown when the image is horizontally centered. |
::part(snap-line-x)
|
snap-line-y |
The horizontal snap line shown when the image is vertically centered. |
::part(snap-line-y)
|
crosshair |
The marker at the center of the crop selection, shown while dragging or panning. |
::part(crosshair)
|
handle |
All drag handles. |
::part(handle)
|
handle-corner |
The corner handles only. |
::part(handle-corner)
|
handle-edge |
The edge handles only. |
::part(handle-edge)
|
toolbar |
The container for the toolbar slot, shown beneath the cropper.
|
::part(toolbar)
|
Custom States Jump to heading
Cropper has the following custom states. You can target them with CSS using the selectors shown below. Learn more about custom states
| Name | Description | CSS selector |
|---|---|---|
loading |
Applied while the image is loading. |
:state(loading)
|
loaded |
Applied once the image has loaded. |
:state(loaded)
|
error |
Applied when the image failed to load. |
:state(error)
|
dragging |
Applied while the user is dragging the crop box. |
:state(dragging)
|
panning |
Applied while the user is panning the image. |
:state(panning)
|
snap-x |
Applied while the image is snapped to the viewport's horizontal center. |
:state(snap-x)
|
snap-y |
Applied while the image is snapped to the viewport's vertical center. |
:state(snap-y)
|
can-pan |
Applied while the image has pan headroom (zoomed and/or rotated) and panning is permitted. |
:state(can-pan)
|
zooming |
Applied while the user is zooming the image. |
:state(zooming)
|
interacting |
Applied during any active pointer gesture (suppresses the settle transition). |
:state(interacting)
|
settling |
Applied briefly while the crop box animates to a new position. |
:state(settling)
|
bouncing |
Applied briefly while the selection bounces (centering or resetting when already in place). |
:state(bouncing)
|
disabled |
Applied when the cropper is disabled. |
:state(disabled)
|
readonly |
Applied when the cropper is read-only. |
:state(readonly)
|
Dependencies Jump to heading
Cropper automatically imports the following elements. Sub-dependencies are also included in this list.