Adding custom validation rules based on another field in Sanity.io

11 replies
Last updated: May 10, 2024
Hi everyone,
I'm just wondering how can I add some custom validation rules based on another field.

So say I have X set in one field and I want to make U field required how could I achieve this with the rule.custom function from the validation property
May 10, 2024, 4:44 PM
This is what i've tried so far with no luck, what is the validation rule expecting to return ?

validation: (rule) =>

rule.custom((value, context) => {

console.log("validation value", value);

console.log("context", context?.parent?.types ?? []);


if (

context?.parent?.types?.includes(SERVICE_PROVIDER_TYPE.HEALTHCARE_PROVIDER) &&

(value?.length ?? 0) === 0

) {

return rule.required();

}


return false;

}),
May 10, 2024, 4:47 PM
Regarding the return type this is what the docs say:
Sometimes you will need to validate values beyond what Sanity provides. The custom() method allows you to do this. It takes a function as the first argument, which should return either true (in the case of a valid value) or an error message as a string (in the case of an invalid value).
May 10, 2024, 5:54 PM
btw I think you can write
(value?.length ?? 0) === 0
as
!value?.length
as well
May 10, 2024, 5:55 PM
Hope that helps
May 10, 2024, 5:56 PM
Ah my bad I've completely missed that section, that makes more sense now thinking about it.
I ended up with something like this:


defineField({

name: "conditionTypes",

title: "Condition severity",

type: "array",

of: [{ type: "string" }],

validation: (rule) =>

rule.custom((value, context) => {

console.log("validation value", value);

console.log("types field value", context?.parent?.types ?? []);


if (context?.parent?.types?.includes(SERVICE_PROVIDER_TYPE.HEALTHCARE_PROVIDER) && !value?.length) {

return "Required";

}


return true;

}),

// If the "types" doesn't include the HEALTHCARE_PROVIDER value then hide this field, it's only applicable for service providers who offer HEALTHCARE_PROVIDER

hidden: ({ parent, value }) => !parent?.types?.includes(SERVICE_PROVIDER_TYPE.HEALTHCARE_PROVIDER) ?? true,

options: {

list: CONDITION_SEVERITY_OPTIONS?.map((conditionSeverity) => ({

title: conditionSeverity.label,

value: conditionSeverity.value

}))

}

})
May 10, 2024, 6:19 PM
I guess if using rule.custom() you have to do all of the sanity checks yourself so you can't chain then together which probably makes sense in a way.
May 10, 2024, 6:32 PM
No you can chain them but not inside the custom function as far as I am aware.
May 10, 2024, 6:38 PM
Example from my own codebase:
validation: (rule: Rule) => [
    rule.required(),
    rule.custom(validateSlug),
    rule.custom(maxLengthSlug(60)).warning(),
]
May 10, 2024, 6:38 PM
Ah cool that seems cool, what if one of those checks is condition if x is set make y required ? I take it you would just need to switch our required for a custom like you did for validating a slug.
May 10, 2024, 6:47 PM
Yes I think for that kind of logic you would need to go full custom and write your own implementation, for this example required goes first as the other validations don’t have to run with 0 input.
May 10, 2024, 7:05 PM
Coolio. Appreciate the responses 😄 All makes sense now 👍
May 10, 2024, 7:06 PM

Sanity– build remarkable experiences at scale

Sanity is a modern headless CMS that treats content as data to power your digital business. Free to get started, and pay-as-you-go on all plans.

Was this answer helpful?