
Grab your gear: The official Sanity swag store
Read Grab your gear: The official Sanity swag storeYes, 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:
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}
},
})
}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}}})
}renderDefault to render Sanity's default string input with your dynamic listuseState, useEffect, useFormValue, useClient, etc.)options.list, but using custom components is the official workaroundThis pattern is quite flexible and handles most dynamic list scenarios you'll encounter!
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.
Content operations
Content backend


The only platform powering content operations
By Industry


Tecovas strengthens their customer connections
Build and Share

Grab your gear: The official Sanity swag store
Read Grab your gear: The official Sanity swag store