Passing parent object attributes to child fields in Sanity schema

6 replies
Last updated: Dec 8, 2021
Is it possible to pass down attributes of an object like you would a React component? eg.

{
 name: 'someField',
 customAttribute: 'foo',
 type: array,
 fields: [
   {
   name: 'child',
   type: 'string',
   inheritedAttribute: parent.customAttribute,
   validation: Rule = Rule.max(inheritedAttribute)
   }.
 ]
}
Trying to use as simple validation as possible on the lowest possible level field to avoid some issues we are having with complex validation.
AI Update

Unfortunately, Sanity schemas don't support directly passing down attributes from parent fields to child fields the way you might pass props in React. The schema definition is a static configuration object, not a component tree with props flowing down.

However, there are a few approaches you can use to achieve similar validation patterns:

1. Access Parent Context in Validation

The validation Rule provides access to parent field values through the context parameter. You can reference the parent's value in child field validation:

{
  name: 'someField',
  type: 'array',
  of: [{
    type: 'object',
    fields: [
      {
        name: 'maxLength',
        type: 'number'
      },
      {
        name: 'child',
        type: 'string',
        validation: (Rule) => Rule.custom((value, context) => {
          // Access the parent object (the array item)
          const maxLength = context.parent?.maxLength
          if (maxLength && value && value.length > maxLength) {
            return `Must be ${maxLength} characters or less`
          }
          return true
        })
      }
    ]
  }]
}

The context parameter in validation functions gives you access to:

  • context.parent - the immediate parent object
  • context.document - the entire document being edited

2. Use Shared Validation Functions

If you need to reuse the same validation logic across multiple fields, define it as a function:

const createMaxLengthValidation = (maxLength: number) => {
  return (Rule) => Rule.max(maxLength)
}

// Then use it in multiple places
{
  name: 'field1',
  type: 'string',
  validation: createMaxLengthValidation(50)
},
{
  name: 'field2', 
  type: 'string',
  validation: createMaxLengthValidation(50)
}

3. Dynamic Validation Based on Document Fields

For validation that depends on other parts of the document, use context.document:

{
  name: 'child',
  type: 'string',
  validation: (Rule) => Rule.custom((value, context) => {
    const configValue = context.document?.someConfigField
    if (configValue && value && value.length > configValue) {
      return `Must be ${configValue} characters or less`
    }
    return true
  })
}

The key limitation is that schema definitions are static - you can't reference parent.customAttribute directly in the schema object. But you can access parent and document values dynamically at validation time through the context parameter, which should help you implement validation at the lowest field level without complex nested validation logic.

Show original thread
6 replies
Hi Jeremy,
did you get solution to pass the attributes down to child objects?
You can't pass down attributes like this, but if you move the validation to the parent array you can set it up to validate its children .
Hey
user Q
and
user M
- I did find a solution and that is to make a ‘functional component’ ie. A function that returns a JSON object in Sanity’s format. This way you can handle inheritance kind of like you would a callback or React props.
import customValidations from "../helpers/customValidations";
import FilteredLocaleBlock from '../custom-inputs/filteredLocaleBlock'


const filteredLocaleImage = (options) => {
    
    const validOptions = {
        // TODO file types should be an array to support multiple valid files
        fileType: 'string',
        maxHeight: 'number',
        maxWidth: 'number',
    }
    
    // Checks Option structure before building object
    if( customValidations.validateOptions(options, validOptions) ) {
        
        return {
            name: 'filteredLocaleImage',
            title: 'Image',
            type: 'object',
            fieldsets: [{
                title: 'Translations',
                name: 'translationsImage',
                options: {
                    collapsible: true
                }
            }],
            
            fields: [{
                name: "baseImage",
                title: "Base English",
                type: 'image',
                options: {
                    collapsible: false
                },
                validation: Rule => Rule.required().custom((Image) => {
                    
                    // Only run validation where base Image exists
                    if(Image){
                        const baseImageValidation = customValidations.validateImage(Image, options.fileType, options.maxWidth, options.maxHeight)
                        if(typeof baseImageValidation === 'string'){
                            return baseImageValidation
                        }
                    }
                    return true
                    
                })
            },
            {
                name: "localisedImage",
                type: "localeImage",
                inputComponent: FilteredLocaleBlock,
                title: "Image",
                fieldset: 'translationsImage',
                validation: Rule => Rule.custom((Image) => {
                    
                    // Only run validation where base Image exists
                    if(Image){
                        const baseImageValidation = customValidations.validateImage(Image, options.fileType, options.maxWidth, options.maxHeight)
                        if(typeof baseImageValidation === 'string'){
                            return baseImageValidation
                        }
                    }
                    return true
                    
                })
            }
        ]
    }
}
}
This way you can pass rules down to the exact image that has the error and get more accurate error reporting - we found the solution
user M
recommends is good for validating a simple object and it’s children but since we have a bit more complex a structure the functional workflow allowed for more flexibility
Thanks for sharing,
user T
!

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?