How AI is powering better personalization in e-commerce [with Vercel]. Sign up now

Dynamically populate list values for string type in Sanity

3 repliesLast updated: Nov 29, 2025

is it possible to dynamically populate the values in a list for a
string
type?
AI Update

Yes, it is definitely possible to dynamically populate the values in a list for a string type! While Sanity doesn't natively support passing a function directly to options.list in your schema definition, there's a well-established workaround using a custom input component.

The approach involves creating a custom component that uses React hooks to fetch or compute your list options dynamically, then passes them to the default string input using renderDefault. Here's how it works:

Basic Example

In your schema, define a string field with an empty list and add any custom options you need:

{
  name: 'region',
  type: 'string',
  options: {
    list: [], // Start with empty list
    // Add any custom options your component will use
  },
  components: {
    input: DynamicListInput,
  },
}

Then create a custom input component that populates the list:

import {useState, useEffect} from 'react'

const DynamicListInput = (props) => {
  const [listItems, setListItems] = useState([])
  const {schemaType, renderDefault} = props

  useEffect(() => {
    // Your logic to populate list items
    const items = [
      {title: 'Option 1', value: 'option1'},
      {title: 'Option 2', value: 'option2'},
    ]
    setListItems(items)
  }, [])

  return renderDefault({
    ...props,
    schemaType: {
      ...schemaType, 
      options: {...schemaType.options, list: listItems}
    },
  })
}

Common Use Cases

1. Based on other field values - Use useFormValue to read other fields in the same document:

import {useFormValue} from 'sanity'

const RegionInput = (props) => {
  const country = useFormValue(['country']) // Read 'country' field
  const [regions, setRegions] = useState([])

  useEffect(() => {
    // Filter regions based on selected country
    const filteredRegions = getRegionsForCountry(country)
    setRegions(filteredRegions)
  }, [country])

  return props.renderDefault({
    ...props,
    schemaType: {...props.schemaType, options: {...props.schemaType.options, list: regions}}
  })
}

2. From external APIs - The Asynchronous List Options Component recipe shows fetching from an API:

useEffect(() => {
  fetch('https://api.example.com/options')
    .then(res => res.json())
    .then(data => setListItems(data))
}, [])

3. From Sanity queries - Use useClient to query your content:

import {useClient} from 'sanity'

const QueryBasedList = (props) => {
  const client = useClient({apiVersion: '2023-01-01'})
  const [options, setOptions] = useState([])

  useEffect(() => {
    client.fetch('*[_type == "category"]{title, "value": slug.current}')
      .then(setOptions)
  }, [client])

  return props.renderDefault({...props, schemaType: {...props.schemaType, options: {...props.schemaType.options, list: options}}})
}

Important Notes

This pattern is quite flexible and handles most dynamic list scenarios you'll encounter!

Show original thread
3 replies

Was this answer helpful?

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.

Related contributions