Skip to content

Cropper

<quiet-cropper> stable since 5.3

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 headers (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.

Preview
<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.

Free Square 16:9 4:3
<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.

Zoom out Zoom in
<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.

Randomize
<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.

Reset
<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
+ arrow Nudges the selection by ten pixels
+ arrow Resizes from the bottom-right corner
+ - Zooms in and out
while dragging a handle Constrains the selection to a square (no effect when aspect-ratio is set)
(or ) while moving or panning 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.

CDN Self-hosted

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.

Search this website Toggle dark mode View the code on GitHub Follow @quietui.org on Bluesky Follow @quiet_ui on X

    No results found