How to preview title instead of value in string options list?

1 replies
Last updated: Oct 4, 2021
Hey guys, I'm wondering how do you preview the
title
in a string options list in both sanity, and also in the front-end?
This list example from the
String Schema Type Docs shows how to preview the lowercase string value, but I'm wondering if there is a way to preview the title string instead, since the title string is more human-readable?
In the sanity-gatsby-portfolio starter, the projectMember object has a list of roles that are selectable for each person that you add as a projectMember to a project. The preview property looks like this:

//studio/schemas/objects/projectMember.js

export default {
  type: 'object',
  name: 'projectMember',
  title: 'Project Member',
  fields: [
    {
      title: 'Person',
      name: 'person',
      type: 'reference',
      to: {type: 'person'}
    },
    {
      title: 'Roles',
      name: 'roles',
      type: 'array',
      of: [{type: 'string'}],
      options: {
        layout: 'radio',
        list: [
          {title: 'Content Designer', value: 'content'},
          {title: 'Director', value: 'director'},
          {title: 'Engineer', value: 'engineer'},
          {title: 'Engineering Manager', value: 'engineeringManager'},
          {title: 'Product Designer', value: 'designer'},
          {title: 'Product Manager', value: 'manager'},
          {title: 'Subject Matter Expert', value: 'sme'},
          {title: 'Technical Writer', value: 'technicalWriter'},
          {title: 'UX Researcher', value: 'researcher'}
        ]
      }
    }
  ],
  preview: {
    select: {
      personName: 'person.name',
      roles: 'roles',
      media: 'person.image'
    },
    prepare (data) {
      return {
        ...data,
        title: data.personName,
        subtitle: data.roles && data.roles.join('/')
      }
    }
  }
}
I've tried
data.roles.title
and passing
roles.title
into the select object but they both don't return anything. When I try and inspect the document, the value is only shown, and the title isn't available, which begs the question if the title field is even able to be passed into other previews or onto the front-end. If not, then should we maintain the value field as lowercase or can we use display formatting in those fields?
AI Update

I can see exactly what you're running into! The short answer is: the title from string list options is not stored in your documents – only the value is saved. This means you can't directly access the title in previews or on the front-end without mapping it yourself.

Looking at your projectMember example, when you save roles like ['content', 'director'], that's literally what gets stored in the database. The titles ("Content Designer", "Director") are just UI labels for the Studio interface.

Solutions

1. Map values to titles in the prepare function

You can create a mapping object to convert values back to titles:

preview: {
  select: {
    personName: 'person.name',
    roles: 'roles',
    media: 'person.image'
  },
  prepare(data) {
    const roleMap = {
      content: 'Content Designer',
      director: 'Director',
      engineer: 'Engineer',
      engineeringManager: 'Engineering Manager',
      designer: 'Product Designer',
      manager: 'Product Manager',
      sme: 'Subject Matter Expert',
      technicalWriter: 'Technical Writer',
      researcher: 'UX Researcher'
    }
    
    return {
      ...data,
      title: data.personName,
      subtitle: data.roles && data.roles.map(role => roleMap[role]).join(' / ')
    }
  }
}

2. Use the same mapping on the front-end

In your Gatsby (or any front-end) code, you'll need the same mapping logic:

const roleMap = {
  content: 'Content Designer',
  director: 'Director',
  // ... etc
}

const displayRoles = roles.map(role => roleMap[role])

3. Alternative: Use human-readable values

If you don't need the short values for anything specific (like CSS classes or API keys), you could just use human-readable strings as both the title AND value:

options: {
  layout: 'radio',
  list: [
    {title: 'Content Designer', value: 'Content Designer'},
    {title: 'Director', value: 'Director'},
    // or even simpler:
    'Content Designer',
    'Director',
    'Engineer'
  ]
}

This way, the readable text gets stored directly and you don't need mapping logic anywhere.

Why it works this way

As mentioned in the preview configuration documentation, title values in list options are UI-only and not stored in the database. This is by design – it keeps your data layer clean and allows you to change UI labels without migrating data.

The trade-off is that you need to maintain the mapping in your code, but this gives you flexibility to display different labels in different contexts (Studio vs. front-end, different languages, etc.).

Show original thread
1 reply
Hi
user R
- unfortunately, you'll have to either duplicate these titles, or create a common enum that both the front-end and studio can use. The
title
is only decorative and for studio use.
You
can write whatever value you want into the
value
field, but "best practice" is to keep those values simple and translatable, by using enums.

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?