Display string list option title in preview subtitle

14 replies
Last updated: Aug 12, 2021
Hi there! I have what feels to me a fairly simple schema, and I’m trying to generate a preview subtitle based on the selected option from a string list.
I’ve read the Previews/List Views documentation page and I’ve tried a number of different syntaxes, but I can’t seem to land on the proper one.

Here’s the schema, with one of my attempts:


name: 'landmark',
type: 'document',
title: 'Landmark',
fields: [
  {
    name: 'title',
    type: 'string',
    title: 'Name of the landmark'
  },
  {
    name: 'country',
    type: 'string',
    title: 'Country',
    options: {
      list: [
        { title: 'United States', value: 'usa' },
        { title: 'France', value: 'fr' }
      ]
    }
  }
],
preview: {
  select: {
    title: 'title',
    subtitle: 'country.title'
  }
}
I would like the list preview to say something like:


Eiffel Tower
France
Statue of Liberty
United States
AI Update

The issue you're running into is that country is a plain string field, not a reference, so country.title doesn't work. When you use a string field with a list of options, only the value (like 'usa' or 'fr') is stored in your document—not the title.

To display the title (like "United States" or "France") in your preview, you need to use the prepare function to map the value back to its title. Here's how to fix your schema:

{
  name: 'landmark',
  type: 'document',
  title: 'Landmark',
  fields: [
    {
      name: 'title',
      type: 'string',
      title: 'Name of the landmark'
    },
    {
      name: 'country',
      type: 'string',
      title: 'Country',
      options: {
        list: [
          { title: 'United States', value: 'usa' },
          { title: 'France', value: 'fr' }
        ]
      }
    }
  ],
  preview: {
    select: {
      title: 'title',
      countryValue: 'country'  // Select the country value
    },
    prepare({title, countryValue}) {
      // Map the value back to its title
      const countryMap = {
        'usa': 'United States',
        'fr': 'France'
      };
      
      return {
        title: title,
        subtitle: countryMap[countryValue] || countryValue
      }
    }
  }
}

This approach uses the prepare function to transform the stored value into the display title. The select object extracts the raw country value, then prepare looks it up in a mapping object to get the human-readable title.

The key insight from the Preview Configuration documentation is that when you have a string field with options, only the value is stored—the title is just for the UI dropdown. To display the title in previews, you need to manually map it back using prepare.

If you find yourself doing this mapping frequently, you might consider extracting the country list to a constant that you can reuse:

const COUNTRIES = [
  { title: 'United States', value: 'usa' },
  { title: 'France', value: 'fr' }
];

const countryMap = Object.fromEntries(
  COUNTRIES.map(c => [c.value, c.title])
);

// Then use COUNTRIES in your field options and countryMap in prepare

This keeps your code DRY and makes it easier to add more countries later!

Show original thread
14 replies
Hi!If I remember correctly, you can only retrieve list values inside the preview, not titles.
In my case I define the list options in a separate variables above.
const countries = [...]
then
list: countries
and in prepare
prepare: { select: { title: 'title', country: 'country'}, prepare({title, country}) 
return {
 title,
subtitle: countries[country]
}
}
(might also be worth to check for
undefined
)
Thanks! I’ve given it a try, but it doesn’t seem to be working quite yet. Here is my new schema:
const countries = [
  { title: 'United States', value: 'usa' },
  { title: 'France', value: 'fr' }
]
export default {
  name: 'landmark',
  type: 'document',
  title: 'Landmark',
  fields: [
    {
      name: 'title',
      type: 'string',
      title: 'Name of the landmark'
    },
    {
      name: 'country',
      type: 'string',
      title: 'Country',
      options: {
        list: countries
      }
    }
  ],
  preview: {
    select: {
      title: 'title',
      country: 'country'
    },
    prepare ({ title, country }) {
      return {
        title,
        subtitle: countries[country]
      }
    }
  }
}
ah oups, I made a mistake. Here's I did it in a real live project:
https://github.com/mornir/terminofeu-studio/blob/master/schemas/objects/illustration.js#L51
In your case, it would be something like
prepare({ 
countryCodetitlemedia }) {      const subtitle = countries.find((
country) => country.value === countryCode).title
you need to use array.find to get the right country
Apologies if I’m slow to catch on… where does
countryCode
come from?
Ah. Looks like it’s a bug. 🤷‍♂️ I’ll stop trying to figure this out and wait for the fix. https://github.com/sanity-io/sanity/issues/2631
Thanks again for your patience on this one, Matt. Please let us know if 2.14.0 doesn't settle this for you.
Hooray!
I tried so many things before I figured out it was a bug, and I’m still not sure what the syntax should be. Here is my (simplified) current attempt, which doesn’t seem to work:

documents/landmark.js

export default {
  name: 'landmark',
  type: 'document',
  title: 'Landmark',
  fields: [{
      name: 'title',
      type: 'string',
      title: 'Name of the landmark'
    },
    {
      name: 'countryAndRegion',
      type: 'countryAndRegion',
      title: 'Country and Region',
    }
  ],
  preview: {
    select: {
      title: 'title',
      subtitle: 'countryAndRegion.country.title'
    }
  }
}
objects/countryAndRegion.js

export default {
  name: 'countryAndRegion',
  type: 'object',
  title: 'Country and Region',
  fields: [{
      name: 'country',
      type: 'string',
      title: 'Country',
      options: {
        list: [
          { title: 'United States', value: 'usa' },
          { title: 'France', value: 'fr' }
        ]
      }
    },
    {
      name: 'region',
      type: 'string',
      title: 'Region'
    }
  ]
}
This does not return anything. If I just do
subtitle: 'countryAndRegion.country'
it returns the
value
.
I’m sure it will seem obvious when you tell me, but I’m a little stumped.
Hold on. I might not have updated properly.
I hadn’t updated properly. But now that I have, the above still doesn’t seem to work. I assume it’s user error and not that it isn’t fixed.
Update: It occurred to me that I don’t really need the country codes. So I’ve simplified it to just a list of keyless country name strings, and that works more smoothly. I think I added them because all of the examples I saw had key:value combinations in list fields.
I love to learn, so I’m still curious how to accomplish the proper list preview given a list of objects.

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?