Form Integration

Submit crop data with standard HTML forms using ElementInternals.

How It Works

<crop-image> is a form-associated custom element. When you set the name attribute, it participates in form submission just like a native <input>.

The form value is automatically set to the RIAPI querystring of the current crop selection. It updates on every crop-change and crop-commit event.

Basic Form Submission

<form action="/api/upload" method="POST" enctype="multipart/form-data">
  <input type="file" name="image" accept="image/*">

  <crop-image
    name="crop"
    src="/preview.jpg"
    aspect-ratio="16/9"
    adapter="imageflow"
  ></crop-image>

  <button type="submit">Upload & Crop</button>
</form>

When submitted, the form data includes:

image: [file data]
crop: ?crop=0.1,0.1,0.9,0.9&cropxunits=1&cropyunits=1

Reading Form Data in JavaScript

const form = document.querySelector('form');

form.addEventListener('submit', (e) => {
  e.preventDefault();
  const data = new FormData(form);
  const cropQs = data.get('crop');
  console.log(cropQs);
  // "?crop=0.1,0.1,0.9,0.9&cropxunits=1&cropyunits=1"
});

Form Properties

The element exposes standard form-associated properties:

PropertyTypeDescription
.formHTMLFormElement | nullThe containing form element
.namestring | nullThe form field name (from the name attribute)
.type'crop-image'The element's form type identifier
.validityValidityStateValidity state (always valid)
.validationMessagestringValidation message (always empty)

Hidden Input Alternative

If you prefer a hidden input (for broader browser support or framework compatibility), mirror the querystring manually:

<form action="/api/crop" method="POST">
  <input type="hidden" name="crop" id="crop-input">

  <crop-image
    src="/photo.jpg"
    adapter="imageflow"
  ></crop-image>

  <button type="submit">Save</button>
</form>

<script type="module">
  import '@imazen/crop-image';

  const cropper = document.querySelector('crop-image');
  const input = document.getElementById('crop-input');

  cropper.addEventListener('crop-commit', (e) => {
    input.value = e.detail.riapi.querystring;
  });
</script>

Multiple Crop Fields

Use different name attributes for multiple crop elements in one form:

<form>
  <crop-image name="thumbnail" src="/photo.jpg" aspect-ratio="1/1"></crop-image>
  <crop-image name="banner" src="/photo.jpg" aspect-ratio="16/9"></crop-image>
  <button type="submit">Save Crops</button>
</form>

Form data will include both:

thumbnail: ?crop=0.2,0.1,0.8,0.7&cropxunits=1&cropyunits=1
banner: ?crop=0.0,0.2,1.0,0.8&cropxunits=1&cropyunits=1

Server-Side Usage

The RIAPI querystring format is natively understood by:

For the generic adapter, the crop coordinates are 0..1 fractions. To convert to pixels server-side, multiply by the source image dimensions:

# Python example
crop_str = request.form['crop']  # "0.1,0.2,0.9,0.8"
x1, y1, x2, y2 = [float(v) for v in crop_str.split(',')]

pixel_x1 = int(x1 * source_width)
pixel_y1 = int(y1 * source_height)
pixel_x2 = int(x2 * source_width)
pixel_y2 = int(y2 * source_height)

Browser support: ElementInternals and form-associated custom elements are supported in all modern browsers (Chrome 77+, Firefox 98+, Safari 16.4+). For older browsers, use the hidden input approach.