✨Discover storytelling in the AI age with Pixar's Matthew Luhn at Sanity Connect, May 8th—register now

Limiting array fields and hiding the "Add Item" button in Sanity.io

7 replies
Last updated: Apr 26, 2021
Is there a way to limit an array field to exactly 6 items and hide the
+ Add Item
button?
Apr 25, 2021, 11:20 AM
You could restrict your array to six and only six items with a validation like this (there are other ways, too):

validation: Rule => Rule.required().min(6).max(6)
This would prevent publishing the document in the studio if the number of items is not six. Note that this will not prevent more or less items when the document is created or edited outside of the studio (the CLI, a client, the HTTP API, etc.), as validation currently only works in the studio.

Removing the
Add item
button (or perhaps more appropriate would be to make it disabled) will take more work. I don’t believe you can easily hijack the button without re-creating the entire input component yourself and building in that logic, but I would be delighted to be proven wrong.
Apr 25, 2021, 4:00 PM
We use a custom snippet that overrides the array Add item button based on an integer based validation rule, It was shared a while back:

https://gist.github.com/Grsmto/cc4db257d05898ca60a9572511fa9bcf .
It requires the code being saved to the project and the part being overridden in the sanity.json

{
      
"implements": "part:@sanity/form-builder/input/array/functions",
      
"path": "./src/components/customArrayFunctions.js"
    
},

We have yet to find any conflicting issues with the snippet so far.
Apr 25, 2021, 4:06 PM
Cool! Thanks for posting this,
user G
. I played around with your snippet to try to implement Sanity UI and get it looking like the buttons in their current version of the studio (full width buttons). Here’s that effort, which is only minimally tested so far:

// Ported from <https://gist.github.com/Grsmto/cc4db257d05898ca60a9572511fa9bcf>

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
  }

  const maxLength = type.validation[0]._rules.find(
    (rule) => rule.flag === "max"
  );

  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) &&
                  (<http://memberDef.to|memberDef.to> || []).length === 1 &&
                  <http://memberDef.to[0].icon|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>
  );
}
Apr 25, 2021, 5:33 PM
This looks very nice! I’ll give it a try tomorrow, but looks very promising
Apr 25, 2021, 6:11 PM
Thanks
user G
&amp;
user A
! I’ve also been looking for a solution for limiting arrays. I’ve actually been trying to create a custom component this weekend with no success. Unfortunately both of the snippets above don’t work for me either, I get the error ‘onCreateValue is not a function’. Neither onCreateValue or onAppendItem are available as props – I can’t figure out why this is? (Sorry for hijacking this thread with my own problem
user D
, have you got it working?)
Apr 26, 2021, 10:12 AM
Credit to
user M
for the original gist! Unfortunately I've haven't messed around with it too much and only use it in it's current scope, working with the required.max() schema validation rule and not passing anythign else to it.
I love the look of
user A
's implementation with the new Sanity UI as well, though I cant figure out how to get the array item list to appear above (popover) as they did previously when nesting components. At this current time they simply extend the parent container.
Apr 26, 2021, 10:24 AM
I’ve realised my issue with onCreateValue &amp; onAppendItem came from using the component as an inputComponent rather than adding it to the sanity.js file. It’s now working for me! 😀
Apr 26, 2021, 1:02 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?