Remove 'add item' button when array length validation is met

25 replies
Last updated: Dec 2, 2025
Hi Everyone!
I’m using an
array
with a
length validation
to limit the Array to 2 array items. Is there a way to remove the ‘add item’ button to disappear when the length validation is met?
AI Update

Unfortunately, Sanity Studio doesn't provide a built-in way to automatically hide the "Add Item" button when an array reaches its maximum validation length. The validation system will prevent publishing if the limit is exceeded, but the UI won't automatically adapt to disable or hide the add functionality.

However, you can achieve this with a custom input component that conditionally renders the array interface based on the current length. Here's the proper approach:

Solution: Custom Array Input Component

The key is to create a custom component that checks the array length against your validation rules and uses renderDefault with modified props to control the array's behavior:

// customArrayInput.js
import {ArrayOfObjectsInputProps} from 'sanity'
import {Stack, Text} from '@sanity/ui'

export function LimitedArrayInput(props: ArrayOfObjectsInputProps) {
  const {value = [], schemaType} = props
  
  // Extract max length from validation rules
  const maxRule = schemaType.validation
    ?.flatMap(v => v._rules || [])
    ?.find(rule => rule.flag === 'max')
  
  const maxLength = maxRule?.constraint
  const currentLength = value.length
  const isAtMax = maxLength && currentLength >= maxLength
  
  // When at max, render with readOnly to prevent adding more items
  if (isAtMax) {
    return (
      <Stack space={3}>
        {props.renderDefault({
          ...props,
          readOnly: true // This makes the entire array read-only
        })}
        <Text size={1} muted>
          Maximum of {maxLength} items reached. Remove an item to add more.
        </Text>
      </Stack>
    )
  }
  
  // Otherwise render normally
  return props.renderDefault(props)
}

Configure in Your Schema

Add the custom component to your array field definition using the components.input property:

import {defineField, defineArrayMember} from 'sanity'
import {LimitedArrayInput} from './customArrayInput'

export default defineField({
  name: 'myArray',
  type: 'array',
  title: 'My Limited Array',
  of: [
    defineArrayMember({type: 'string'})
  ],
  validation: Rule => Rule.max(2),
  components: {
    input: LimitedArrayInput
  }
})

Important Limitations

The approach above uses readOnly: true, which makes the entire array read-only when the limit is reached. This means:

  • ✅ Users cannot add new items (the add button becomes disabled)
  • ❌ Users also cannot edit or remove existing items while at the limit

If you need users to be able to remove items while at the max (so they can swap items), you'll need a more complex solution that fully reimplements the array input rather than using renderDefault.

Alternative: Conditional Field

Another approach is to use conditional fields to make the entire array field read-only based on its length:

defineField({
  name: 'myArray',
  type: 'array',
  of: [{type: 'string'}],
  validation: Rule => Rule.max(2),
  readOnly: ({value}) => (value || []).length >= 2
})

This has the same limitation as above – the entire field becomes read-only at the limit.

Why This Is Tricky

The reason there's no simple "hide add button" option is that Sanity's array input component is complex, handling drag-and-drop reordering, item editing, validation display, and more. The renderDefault function gives you the complete default component, but you can't easily modify just one aspect of it (like hiding a specific button) without reimplementing the entire component.

For most use cases, the read-only approach above strikes a good balance between customization effort and user experience – it clearly communicates that the limit has been reached while preventing further additions.

Show original thread
25 replies

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?