How to display custom icons in array item previews from referenced documents?

12 replies
Last updated: Dec 21, 2022
Hello! I'm having trouble changing icons in elements of an array.
So, I have a schema type called category. I've given it a preview like this:

preview: {
        select: {
          title: 'categoryName',
          subtitle: 'descriptionShort',
          media: 'icon'
        }
      }
It works in the document list that shows all the categories.
However, I also have a list of some chosen categories in an array in a different document. There the title and the subtitle is as determined by the preview in category, but the icon is the default empty page instead of the one from category. How do I change the icon in an array preview of an element?
AI Update

I understand your issue! When you have an array of references to your category documents, the preview configuration from the category schema doesn't automatically apply to how those references appear in the array. You need to configure the preview on the array field itself, not just on the referenced document type.

Here's how to fix it. In the schema where you have the array of categories, you need to add a preview configuration to the array field definition:

{
  name: 'categories',
  type: 'array',
  of: [
    {
      type: 'reference',
      to: [{type: 'category'}],
      preview: {
        select: {
          title: 'categoryName',
          subtitle: 'descriptionShort',
          media: 'icon'
        }
      }
    }
  ]
}

The key is adding the preview object to the reference definition inside the array's of property. This tells Sanity how to display each reference when it appears in the array.

If you want to access fields from the referenced category document (which is the typical case), you can use dot notation in the select:

{
  name: 'categories',
  type: 'array',
  of: [
    {
      type: 'reference',
      to: [{type: 'category'}],
      preview: {
        select: {
          title: 'categoryName',  // This accesses the referenced category's categoryName
          subtitle: 'descriptionShort',
          media: 'icon'
        }
      }
    }
  ]
}

If you need more control or want to provide fallback icons, you can use the prepare function with a React icon component:

import { TagIcon } from '@sanity/icons'

{
  name: 'categories',
  type: 'array',
  of: [
    {
      type: 'reference',
      to: [{type: 'category'}],
      preview: {
        select: {
          title: 'categoryName',
          subtitle: 'descriptionShort',
          media: 'icon'
        },
        prepare({title, subtitle, media}) {
          return {
            title,
            subtitle,
            media: media ?? TagIcon  // Fallback icon if none exists
          }
        }
      }
    }
  ]
}

The reason this happens is that preview configurations are context-specific in Sanity. The preview you defined on the category document type controls how categories appear in the category document list, but when those same categories are referenced in an array elsewhere, you need to explicitly tell Sanity how to preview them in that context. This gives you flexibility to show different information in different contexts if needed.

For more details on preview configuration, check out the official documentation on previews and list views and this helpful guide on creating richer array item previews.

Show original thread
12 replies
You can set an icon on the schema level (which will be a default fallback) and in the preview like this:
// on the schema level
export default defineType({
  type: 'document',
  name: 'ticket',
  title: 'Ticket',
  liveEdit: true,
  icon: () => <SupportIcon />,
  fields: [...

// in preview
  preview: {
    select: {
      title: 'title',
      alternatives: 'alternatives',
    },
    prepare({alternatives, title}) {
      const subtitle = alternatives !== undefined ? `${alternatives.map((a) => a).join(', ')}` : ''

      return {
        title,
        subtitle,
        media: <SupportIcon />
      }
    },
  },
import {TagIcon} from '@sanity/icons'

export default {
    name: 'category',
    type: 'document',
    title: 'Category',
    icon: TagIcon,
    fields: [
I already have an icon set in the schema and it works in the document list, just not in the reference array.
user J
Sorry for tagging, it's just you added a checkmark to my question when it hasn't been resolved yet.
in the array you need to define the preview 🙂
{
            name: 'featuredCategories',
            type: 'array',
            title: 'Featured Categories',
            of: [{
                type: 'reference',
                to: [
                    {type: 'category'}
                ],
                options: {
                    layout: 'tags',
                },
            }],
            preview: {
                select: {
                    title: 'categoryNameEng'
            }
        },
Adding a preview to the array does nothing. In the docs it also doesn't say that an Array has a preview field or option.

Maybe I'm misunderstanding you. There is quite a few different places I can think of to add the icon. You have the document with the array where it could be either on the objects within the array, or the array itself, or it could be in the document that is referenced either as an icon, or as a preview in the document. But I do think I have tried all of those.
https://www.sanity.io/docs/previews-list-views You need to define the previews in the documents referenced themselves, not the array.
Think of it that way: What are you previewing? You are previewing data from the referenced documents. Hence you need to define it there. You can have multiple doc types referenced in one array, so you need to define all previews within the given doc types.


{
            name: 'contentArray',
            title: 'Content',
            type: 'array',
            // In this array you want to display each of the items in a different way, regardless, if these are objects like this example here, or references to documents ☺️
            of: [
                { type: 'heroSection' },
                { type: 'headerSection' },
                { type: 'textSection' },
                { type: 'cardSection' },
                { type: 'accordionSection' },
                { type: 'furtherLinkSection' },
                { type: 'tabSection' },
                { type: 'cta' }
            ],
        },
Hope that helps
😊
So if you want to only set an icon, you can set an icon in the document schemas as detailed in this message here
I do also have a preview in the referenced document. And when that document is shown in a document list I get the icon, but when it is in the array I do not, but the other fields act in accordance with the preview. Let me add some screenshots to see if that makes it clearer. As seen from the screenshots the icon behaves differently in the document list and in the array of references. In this case I have a preview in the document that is referenced in the array. I changed the title here to a different field than the default to see that it changes in both the document list and in the reference array and that is the case. So both apply the preview, but the icon is only changed in one of the instances.
I'm just bumping this one since I got a checkmark on it without finding a solution to my problem.
You cannot reference icon like you are trying to. Please read my code examples. since icon is NOT a field,
media: "icon"
will not work.You need to pass a react component to media
media: <ICON/>
Ah awesome, thank you! I didn't realize I needed the prepare part from your example. Now it works.
The devil is always in the details right 😉

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?