Validation Rule - Only allow one member in an array.

1 replies
Last updated: Feb 26, 2021
I have a validation rule set to only allow 1 member in an array.But, the “Add” button still shows in the studio...
Would be nice if this was conditional so it would be hidden (or dimmed) when the validation rule takes effect.


{   title:"Merke", 
    name:"manufacturer", 
    type: "array", of: [
         {type:'reference',
          to: [ {type:"manufacturer"}]
         }
     ],
     validation: Rule => Rule.max(1).error('Du kan bare ha ett Merke per kjøretøy. Velg Chassisprodusent ved tvil.'),   
    fieldset:"main"
},

AI Update

Unfortunately, validation rules and the "Add" button in array inputs aren't automatically connected in Sanity Studio. The validation only runs when you try to save or make changes, so the UI doesn't know to hide the button based on your Rule.max(1) validation.

However, you have a couple of good options to achieve this:

Option 1: Use the hidden callback on the array itself

Since you only want one item, you could conditionally hide the entire array field once it has a value:

{
  title: "Merke",
  name: "manufacturer",
  type: "array",
  of: [{
    type: 'reference',
    to: [{type: "manufacturer"}]
  }],
  hidden: ({value}) => value && value.length >= 1, // Hide when array has item
  validation: Rule => Rule.max(1).error('Du kan bare ha ett Merke per kjøretøy.'),
  fieldset: "main"
}

This approach might not be ideal since it hides the entire field, but you could combine it with a custom input component that shows the selected value in a read-only way.

This gives you full control over when to show/hide the "Add" button. Here's a basic example:

import {Stack, Button} from '@sanity/ui'
import {AddIcon} from '@sanity/icons'
import {set, unset, insert} from 'sanity'

function ManufacturerArrayInput(props) {
  const {value = [], onChange, schemaType, renderDefault} = props
  const maxItems = 1
  const canAdd = value.length < maxItems

  // If we're at max capacity, just render the default without Add button
  if (!canAdd) {
    return renderDefault({
      ...props,
      arrayFunctions: () => null // This hides the array functions including Add button
    })
  }

  return renderDefault(props)
}

// In your schema:
{
  title: "Merke",
  name: "manufacturer",
  type: "array",
  of: [{
    type: 'reference',
    to: [{type: "manufacturer"}]
  }],
  components: {
    input: ManufacturerArrayInput
  },
  validation: Rule => Rule.max(1).error('Du kan bare ha ett Merke per kjøretøy.'),
  fieldset: "main"
}

The key here is using renderDefault with modified props. The arrayFunctions prop controls the toolbar that contains the Add button. By returning null when you're at capacity, you hide those controls.

Option 3: Consider using a single reference instead

Since you only want one manufacturer per vehicle anyway, you might want to reconsider using an array at all:

{
  title: "Merke",
  name: "manufacturer",
  type: "reference",
  to: [{type: "manufacturer"}],
  validation: Rule => Rule.required().error('Velg ett merke.'),
  fieldset: "main"
}

This is simpler and the UI naturally supports single selection. You'd just need to update your queries to not expect an array.

The custom input component approach (Option 2) gives you the exact behavior you're looking for while maintaining your current data structure. Check out the custom input components documentation and the guide on creating your first input component for more details on building this out.

Hi Johannes, there's no built-in way to do this for now. However, you could consider customising your array functions. Here's an example that hides the Add button when a max of (1) item is reached, based on the native array component.
To implement it, in your 
sanity.json
 file, add:
{
      "implements": "part:@sanity/form-builder/input/array/functions",
      "path": "./components/CustomArrayFunctions.js"
}
This is the relevant component -  
https://gist.github.com/Grsmto/cc4db257d05898ca60a9572511fa9bcf  (community contribution).
Latest version of the native component for comparison: 
https://github.com/sanity-io/sanity/blob/next/packages/@sanity/form-builder/src/inputs/ArrayInput/ArrayFunctions.tsx

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?