Search code examples
validationsanity

How can I validate the dimensions of an uploaded image in Sanity?


I have an image type field in Sanity (docs) and I need to make sure that the dimensions are within a particular range to avoid breaking the website they're going on. Sanity offers validations, but the image type only has “required” and “custom” rules, and the field information passed into the custom validator doesn't include the image metadata.

How can I work around this limitation and offer in-CMS validation of the dimensions?


Solution

  • While Sanity doesn't pass the image metadata into the validator, you can extract image format and dimension information from the asset ID that is provided. According to this documentation, this is a supported, stable way of accessing this information without loading the image object from Sanity.

    For example, here's the first argument passed to the Rule.custom validator:

    {
      "_type": "image",
      "alt": "Example Image",
      "asset": {
        "_ref": "image-bff149a0b87f5b0e00d9dd364e9ddaa0-700x650-jpg",
        "_type": "reference"
      }
    }
    

    Getting to the image dimensions can be accomplished like this:

    {
      title: "My Image",
      name: "image",
      type: "image",
      options: {
        accept: "image/*",
      },
      validation: Rule => Rule.custom(image => {
        if (!image) return true
        const { dimensions } = decodeAssetId(image.asset._ref)
        return dimensions.width >= 500 || "Image must be wider"
      }
    }
    
    const pattern = /^image-([a-f\d]+)-(\d+x\d+)-(\w+)$/
    
    const decodeAssetId = id => {
      const [, assetId, dimensions, format] = pattern.exec(id)
      const [width, height] = dimensions.split("x").map(v => parseInt(v, 10))
    
      return {
        assetId,
        dimensions: { width, height },
        format,
      }
    }
    

    I have also rolled this functionality into the sanity-pills library that makes it easier to do like this:

    import { createImageField } from "sanity-pills"
    
    createImageField({
      name: "image",
      validations: {
        required: true,
        minWidth: 500,
        maxHeight: 9000
      },
    })