Limit array field to exactly 6 items and hide Add Item button

7 replies
Last updated: Jan 28, 2026
Is there a way to limit an array field to exactly 6 items and hide the
+ Add Item
button?
AI Update

Yes! You can limit an array field to exactly 6 items and hide the "Add Item" button. Here's how to do it:

Validation for exactly 6 items

First, add validation to your array field in the schema:

{
  name: 'myArray',
  type: 'array',
  of: [{type: 'string'}], // or whatever type you need
  validation: Rule => Rule.required().min(6).max(6)
}

This prevents publishing if the array doesn't have exactly 6 items. However, the "Add Item" button will still appear.

Hiding the "Add Item" button

To hide the button when the limit is reached, you'll need to create a custom array input component. Here's a solution that works with Sanity Studio v3:

1. Create a custom component file (e.g., customArrayFunctions.js):

import React from "react";
import {isReferenceSchemaType} from '@sanity/types'
import {AddIcon} from '@sanity/icons'
import {Button, Grid, Menu, MenuButton, MenuItem} from '@sanity/ui'
import {useId} from '@reach/auto-id'

export default function ArrayFunctions(props) {
  const {type, readOnly, children, onCreateValue, onAppendItem, value} = props
  const menuButtonId = useId()

  const insertItem = React.useCallback(
    (itemType) => {
      const item = onCreateValue(itemType)
      onAppendItem(item)
    },
    [onCreateValue, onAppendItem]
  )

  const handleAddBtnClick = React.useCallback(() => {
    insertItem(type.of[0])
  }, [type, insertItem])

  if (readOnly) {
    return null
  }

  // Check for max length validation
  const maxLength = type.validation[0]?._rules.find(
    (rule) => rule.flag === "max"
  );

  // Hide button if max length reached
  if (maxLength && value && value.length >= maxLength.constraint) {
    return null;
  }

  return (
    <Grid gap={1} style={{gridTemplateColumns: 'repeat(auto-fit, minmax(100px, 1fr))'}}>
      {type.of.length === 1 ? (
        <Button icon={AddIcon} mode="ghost" onClick={handleAddBtnClick} text="Add item" />
      ) : (
        <MenuButton
          button={<Button icon={AddIcon} mode="ghost" text="Add item…" />}
          id={menuButtonId || ''}
          menu={
            <Menu>
              {type.of.map((memberDef, i) => {
                const referenceIcon =
                  isReferenceSchemaType(memberDef) &&
                  (memberDef.to || []).length === 1 &&
                  memberDef.to[0].icon

                const icon = memberDef.icon || memberDef.type?.icon || referenceIcon
                return (
                  <MenuItem
                    key={i}
                    text={memberDef.title || memberDef.type?.name}
                    onClick={() => insertItem(memberDef)}
                    icon={icon}
                  />
                )
              })}
            </Menu>
          }
        />
      )}
      {children}
    </Grid>
  );
}

2. Register the component in your sanity.config.js (Studio v3):

import {defineConfig} from 'sanity'
import ArrayFunctions from './customArrayFunctions'

export default defineConfig({
  // ... other config
  form: {
    components: {
      input: (props) => {
        if (props.schemaType.jsonType === 'array') {
          return <ArrayFunctions {...props} />
        }
        return props.renderDefault(props)
      }
    }
  }
})

This solution automatically reads your max() validation rule and hides the "Add Item" button when the array reaches that length. It works with both single-type and multi-type arrays, and uses Sanity UI components to maintain a consistent look with the rest of the Studio.

Credit goes to the Sanity community discussion where this approach was developed and refined. The original gist was created by a community member and adapted by others to work with Sanity UI.

Show original thread
7 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?