How to return title instead of value from string/list in Sanity?
Based on the documentation, I can see this is a common point of confusion! When you define a field with type: 'string' and a list of options in your schema, Sanity stores only the value, not the title/label.
The key thing to understand is that the title in list options is purely for the Studio UI - it's what editors see when selecting options, but it never gets saved to your database. Only the value is stored.
Here's an example schema:
{
name: 'status',
type: 'string',
options: {
list: [
{title: 'In Progress', value: 'in_progress'},
{title: 'Completed', value: 'completed'}
]
}
}When an editor selects "In Progress", your database stores "in_progress".
To display the title in your frontend, you have a few approaches:
- Create a mapping function in your frontend code:
const statusTitles = {
'in_progress': 'In Progress',
'completed': 'Completed'
}
const displayTitle = statusTitles[document.status]- Use GROQ's select() function in your query to map values to titles:
*[_type == "myDoc"] {
statusTitle: select(
status == "in_progress" => "In Progress",
status == "completed" => "Completed",
"Unknown"
)
}- Switch to objects instead of strings if you need both stored:
{
name: 'status',
type: 'object',
fields: [
{name: 'title', type: 'string'},
{name: 'value', type: 'string'}
]
}This is mentioned in the preview configuration documentation - titles in list options are display-only and not stored in the database. Most developers go with option 1 or 2 since it keeps your data clean and normalized.
Show original thread5 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.