How to use Custom Input Components on a Field of Type ‘Object’

1 replies
Last updated: Apr 14, 2020
Hello people of the sanity community! I am trying to get my head around custom input components used on an field of type ‘object’. This is the object in question, I have it as a part of my Product document.

export default {
    title: 'Product Info',
    name: 'productInfo',
    type: 'object',
    fields: [
        {
            title: 'Product Id',
            name: 'productId',
            type: 'number'
        },
        {
            title: 'Product Storage Id',
            name: 'storageId',
            type: 'number'
        },
        {
            title: 'hasAttributes',
            name: 'hasAttributes',
            type: 'boolean'
        },
        
    ]
}
The object has some more attributes but they aren’t needed for this example, so I have a custom input component that prepopulates the product names and respective values with information from our PIM, in order for the user to select a product name from a dropdown and you have all the values you want to set like this as an object:

{ productId: 90922, storageId: 29992, hasAttributes: true }
So my question is, how would I use the PatchEvent set() specified in the documentation for an more complex object than a single string or number? If I provided an object would it be able to map the keys to the fieldnames in the schema? Below is provided of the example from the documentation with the single number.

const createPatchFrom = value => PatchEvent.from(value === '' ? unset() : set(Number(value)))
AI Update

Great question! Yes, you can absolutely pass an object to set() and it will map the keys to the field names in your schema. This is exactly how you'd handle updating complex objects with multiple fields.

Based on your example, here's how you'd update your productInfo object:

const createPatchFrom = (value) => {
  const updates = {
    productId: value.productId,
    storageId: value.storageId,
    hasAttributes: value.hasAttributes
  }
  return PatchEvent.from(set(updates))
}

// Then in your component's onChange handler:
onChange(createPatchFrom({ productId: 90922, storageId: 29992, hasAttributes: true }))

Or more directly:

onChange(PatchEvent.from(set({ 
  productId: 90922, 
  storageId: 29992, 
  hasAttributes: true 
})))

The keys in your object need to match the name fields in your schema definition (which they do in your case: productId, storageId, and hasAttributes). When you pass this object to set(), Sanity will update all those fields at once.

One important thing to remember: PatchEvent.from() is just creating the patch action - you must call it with onChange (which is passed as a prop to your custom input component) for it to actually update the document. A common mistake is creating the PatchEvent but forgetting to invoke onChange.

If you need to ensure the object exists before setting values (useful if the field might be undefined initially), you can chain operations:

onChange(
  PatchEvent.from(set(updates))
    .prepend(setIfMissing({}))
)

This approach works great for your use case where you're populating multiple fields from your PIM dropdown selection. The PatchEvent documentation has more details on how this integrates with Studio's real-time collaboration features.

For anyone having the same problem as I: I figured out that patches from custom input and the http api probably worked the same under the hood. So by looking at the documentation here, https://www.sanity.io/docs/http-patches , I made this work by sending in an object with keys as the field names and values as the new values that I wanted.

user Y
or someone at Sanity, Id love to help extend the documentation for https://www.sanity.io/docs/custom-input-widgets to cover objects as well! Let me know if you want me to write something up that you can look through, edit and publish!

Sanity – Build the way you think, not the way your CMS thinks

Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.

Was this answer helpful?