Populate string list based on another field value in same document
Yes, you can definitely populate a list of predefined strings based on another field's value! This is a common pattern and there are a couple of good approaches depending on your needs.
Custom Input Component (Recommended Approach)
The most flexible solution for your use case is creating a custom input component. This gives you full access to the Sanity client and the useFormValue hook to read values from other fields in the document:
import { useFormValue, useClient, StringInputProps, set } from 'sanity'
import { useEffect, useState } from 'react'
function SubCategoryInput(props: StringInputProps) {
const client = useClient({ apiVersion: '2023-01-01' })
const [options, setOptions] = useState<string[]>([])
// Get the collection reference from the current document
const collectionRef = useFormValue(['collection', '_ref'])
useEffect(() => {
if (!collectionRef) return
// Fetch the collection document and extract sub-categories
client.fetch(
`*[_id == $ref][0].subCategories`,
{ ref: collectionRef }
).then((subCategories) => {
setOptions(subCategories || [])
})
}, [collectionRef, client])
return (
<select
value={props.value || ''}
onChange={(e) => props.onChange(set(e.target.value))}
>
<option value="">Select a sub-category</option>
{options.map(category => (
<option key={category} value={category}>{category}</option>
))}
</select>
)
}
// In your product schema:
{
name: 'subCategory',
type: 'string',
title: 'Sub Category',
components: {
input: SubCategoryInput
}
}You can also check out this community pattern for building async list options.
Alternative: Using References
Consider whether your sub-categories should actually be separate documents that you reference, rather than strings. This approach gives you:
- Better data normalization
- Easier querying and reuse
- Built-in reference selection UI with filtering
// Product schema with filtered references
{
name: 'subCategory',
type: 'reference',
to: [{ type: 'subCategory' }],
options: {
filter: ({ document }) => {
const collectionRef = document.collection?._ref
return {
filter: '_id in *[_id == $collectionRef][0].subCategories[]._ref',
params: { collectionRef }
}
}
}
}Why Not options.list as a Function?
While it would be nice to use options.list as an async function (as discussed in this GitHub issue), it's currently not supported because:
options.listfunctions are synchronous and can't use async operations- You can't directly access the Sanity client within the schema definition
The custom input component approach is the current best practice for dynamic lists that depend on other field values or require data fetching. It gives you full control and access to all the hooks you need.
Show original thread2 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.