Populate array field options list from sibling field in Sanity

3 replies
Last updated: Mar 4, 2024
Hey. Im trying to populate array field list from a sibling field. Is that doable?
There is more to it than this, but I tried to extract the essence.


fields: [
		{
			name: 'colors',
			title: 'colors',
			type: 'array',
			of: [{ type: 'string' }],
		},
		{
			name: 'group',
			title: 'group',
			type: 'array',
			of: [{ type: 'string' }],
			options: {
				layout: 'grid',
				list: [GET VALUES FROM colors FIELD]
			}
		}
	],

AI Update

Yes, this is definitely doable! You can access sibling field values in a custom input component using the path prop that your component receives.

When you create a custom input component, it receives several props including a path array that tells you where in the document structure your field is located. You can use this path to access the parent object, which contains your sibling fields.

Using the path prop

Your custom input component receives a path prop that contains an array representing the field's location in the document. You can slice off the last item to get the parent object's path, then use useFormValue to access that parent and read the sibling field:

import { useFormValue } from 'sanity'

function MyCustomInput(props) {
  const { path } = props
  
  // Get parent path by removing the last segment (current field name)
  const parentPath = path.slice(0, -1)
  
  // Get the parent object which contains both fields
  const parentObject = useFormValue(parentPath)
  
  // Access the colors field from the sibling
  const colors = parentObject?.colors || []
  
  // Now use colors to populate your options
  return (
    <select onChange={(e) => props.onChange(set(e.target.value))}>
      {colors.map(color => (
        <option key={color} value={color}>{color}</option>
      ))}
    </select>
  )
}

Complete example for your use case

import { set, unset } from 'sanity'
import { useFormValue } from 'sanity'

export default {
  name: 'myDocument',
  type: 'document',
  fields: [
    {
      name: 'items',
      type: 'array',
      of: [{
        type: 'object',
        fields: [
          {
            name: 'colors',
            title: 'Colors',
            type: 'array',
            of: [{ type: 'string' }],
          },
          {
            name: 'group',
            title: 'Group',
            type: 'string',
            components: {
              input: GroupInput
            }
          }
        ]
      }]
    }
  ]
}

function GroupInput(props) {
  const { value, onChange, path } = props
  
  // Get parent object containing both colors and group fields
  const parentPath = path.slice(0, -1)
  const parentObject = useFormValue(parentPath)
  const colors = parentObject?.colors || []
  
  return (
    <select 
      value={value || ''}
      onChange={(e) => {
        const newValue = e.target.value
        onChange(newValue ? set(newValue) : unset())
      }}
    >
      <option value="">Select a color</option>
      {colors.map(color => (
        <option key={color} value={color}>{color}</option>
      ))}
    </select>
  )
}

This approach is confirmed in this community answer where someone had the exact same use case. The path prop is the key to accessing sibling fields within array items or objects.

The custom input component will re-render whenever the colors field changes, so your dropdown options will stay in sync with the sibling field automatically. Note that you can't use dynamic functions directly in options.list - you need to create a custom input component like shown above to achieve this dynamic behavior based on sibling field values.

Show original thread
3 replies
You can adapt this component to use the
useFormValue
hook to get the values from the sibling field.
user P
Supert. Tusen takk :)

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?