Conditional validation based on field values in Sanity

26 replies
Last updated: Feb 26, 2021
Is it possible to only apply validation rules if a user fills out a specific input or checks a Boolean within the same object?
AI Update

Yes, absolutely! You can create conditional validation rules that only apply when specific fields are filled out or when a boolean is checked. This is done using custom validation with the custom() method, which gives you access to the context object containing parent field values.

Here's how to implement conditional validation based on different scenarios:

Based on a Boolean Field

defineField({
  name: 'requiresApproval',
  type: 'boolean',
  title: 'Requires Approval'
}),
defineField({
  name: 'approverEmail',
  type: 'string',
  title: 'Approver Email',
  validation: (rule) =>
    rule.custom((value, context) => {
      const requiresApproval = context?.parent?.requiresApproval;
      
      if (requiresApproval && !value) {
        return 'Approver email is required when approval is needed';
      }
      return true;
    }),
})

Based on Another Field Being Filled

defineField({
  name: 'customOption',
  type: 'string',
  title: 'Custom Option'
}),
defineField({
  name: 'customDetails',
  type: 'text',
  title: 'Custom Details',
  validation: (rule) =>
    rule.custom((value, context) => {
      const customOption = context?.parent?.customOption;
      
      if (customOption && !value) {
        return 'Please provide details for your custom option';
      }
      return true;
    }),
})

Based on Specific Field Values

You can also check for specific values, not just whether a field is filled:

defineField({
  name: 'eventType',
  type: 'string',
  options: {
    list: ['online', 'in-person', 'hybrid']
  }
}),
defineField({
  name: 'venue',
  type: 'string',
  validation: (rule) =>
    rule.custom((value, context) => {
      const eventType = context?.parent?.eventType;
      
      if ((eventType === 'in-person' || eventType === 'hybrid') && !value) {
        return 'Venue is required for in-person and hybrid events';
      }
      return true;
    }),
})

Multiple Conditional Checks

You can combine multiple conditions:

validation: (rule) =>
  rule.custom((value, context) => {
    const { isPublished, publishDate, category } = context?.parent || {};
    
    if (isPublished && !publishDate) {
      return 'Publish date is required for published content';
    }
    
    if (category === 'premium' && !value) {
      return 'This field is required for premium content';
    }
    
    return true;
  })

Important Notes

The context?.parent object gives you access to all sibling fields within the same object. Always use optional chaining (?.) to safely access these values, and remember that validation is client-side only in Studio, so you'll need separate server-side validation if you're accepting mutations through the API.

You can also use different validation levels - return an error string to block publishing, or use .warning() or .info() for less critical feedback to editors. More details on context-dependent validation can be found in Sanity's custom validation documentation.

Show original thread
26 replies
https://www.sanity.io/docs/validation the docs mention using context in custom validation methods but I can’t find out what that means or how exactly it’s working.
I also noticed it says you can access the nearest parent, does that mean you can access anything in the parent document from the object being validated?
What is context here
Hi Dustin. I’m assuming a boolean checker called
trigger
and the field you want to (conditionally) validate called `email`:

...

{
  name: 'trigger',
  title: 'Validate',
  type: 'boolean',
},
{
  name: 'email',
  type: 'string',
  title: 'Email',
  validation: Rule => Rule.custom((_, context) => context.document.trigger ? "Email is required" : true)
},

...

Does true validate as passing and the string is the thrown error
Correct
My solution is incomplete. It’s not resolving to true. I will update it and follow up.
Okay, you could try something like this:

validation: Rule => Rule.custom((validate, context) => (context.document.trigger && validate === undefined) ? "Email is required" : true)
did you mean to name the prop
trigger
instead of
validate
?
I’m trying similar validations and I’m not getting any feedback from Sanity
No,
trigger
is part of
context.document
, and we are just checking if it's true.
Validate
is the current field. If you want to post a snippet from your schema we can figure out the correct wording.
{
      name: "title",
      title: "Title",
      description: "Use the correct title",
      type: "string",
      validation: Rule =>
        Rule.custom((title, context) =>
          context.document.deleted && title === undefined
            ? "Title is required"
            : true
        )
    },
Here’s what I’m trying and it isn’t doing anything. It allows me to update the schema without a title and doesnt seem to recognize the deleted boolean
I want to be able to save the document without a title only if the boolean equal to true
Is your boolean
deleted
a sibling of
title
?
yeah here they are in the schema together
    {
      name: "title",
      title: "Title",
      description: "Use the correct title",
      type: "string",
      validation: Rule =>
        Rule.custom((title, context) =>
          context.document.deleted === true && title === undefined
            ? true
            : "Title required"
        )
    },
    {
      name: "deleted",
      title: "Deleted",
      description: "Prevent this variant from being added to the store",
      type: "boolean"
    },
If you want to allow a blank title when the boolean is true, the code will need to be reworked a bit. But I'm surprised it's not at least responding.
well now it’s just blanket requiring the title
true will let the document save in this case, right?
That's right. When it evaluates to true it should permit you to save.
context.document.deleted ? true : "Title required"
this wont even let me publish
It always returns the string
that’s because it’s undefined. Just console.log it. That’s weird
it looks like
context.document.*
always returns undefined.
user A
Alright, i figured it out. I always forget that my Sanity is set up a bit differently than most, so my document actually looks quite a bit different. This is what works for me
 {
      name: "title",
      title: "Title",
      description: "Use the correct title",
      type: "string",
      validation: Rule =>
        Rule.custom((title, context) => {
          const validTitle = title && title !== undefined;
          const isDeleted = context.document.content.main.deleted;
          if (isDeleted && !validTitle) {
            return true;
          } else if (validTitle) {
            return true;
          } else return "Needs a valid title";
        })
    },
my context is set up differently because of tabs I think.
That's good to know. Thanks Dustin. Glad you got it working.

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?