Handling nested references in Sanity preview function

6 replies
Last updated: Feb 8, 2025
Hey everyone! đź‘‹
I’m trying to get a nested array of referenced objects inside the preview function, but I’m running into some issues. My schema looks something like this:


preview: {
  select: {
    cards: 'cards',
    theme: 'cards[].theme.hex',
  },
  prepare({ cards, theme }) {
    return {
      title: 'Dual',
      subtitle: 'Dual Block',
      media: withCustomParams(DualMedia, { cards }),
    };
  },
},
The cards array contains references to another document type, and each referenced document has a theme.hex field. However, I’m not sure how to correctly select the nested theme values from these referenced objects.

I’ve checked the
Sanity docs on previews , but it only covers direct references, not arrays of references.
Is there a recommended way to handle this in select? Or do I need to resolve the references manually in prepare?

Thanks in advance!
🚀
AI Update

Unfortunately, the preview.select syntax in Sanity doesn't support dereferencing arrays of references directly. The syntax cards[].theme.hex won't work because the preview system can't automatically resolve multiple references in an array.

Here's what you need to know based on the preview configuration documentation:

What works:

  • Single references: author.name (dereferences one document)
  • Array indices: cards.0.theme.hex (gets the first item)

What doesn't work:

  • Array dereferencing: cards[].theme.hex or cards[]->theme.hex

Solutions

Option 1: Access Individual Array Items

If you only need a few items from the array, you can select them by index:

preview: {
  select: {
    cards: 'cards',
    theme0: 'cards.0.theme.hex',
    theme1: 'cards.1.theme.hex',
  },
  prepare({ cards, theme0, theme1 }) {
    return {
      title: 'Dual',
      subtitle: 'Dual Block',
      media: withCustomParams(DualMedia, { cards, themes: [theme0, theme1] }),
    };
  },
}

Since the prepare function receives the raw data including reference IDs, you'll need to handle the full resolution in your custom preview component. Pass the cards array as-is and fetch the referenced data in your DualMedia component using a GROQ query:

preview: {
  select: {
    cards: 'cards',
  },
  prepare({ cards }) {
    return {
      title: 'Dual',
      subtitle: 'Dual Block',
      media: withCustomParams(DualMedia, { cards }),
    };
  },
}

Then in your DualMedia component, use the Sanity client to fetch the full referenced documents with their theme data:

import { useEffect, useState } from 'react';
import { client } from './sanityClient';

function DualMedia({ cards }) {
  const [resolvedCards, setResolvedCards] = useState([]);
  
  useEffect(() => {
    if (!cards?.length) return;
    
    const cardIds = cards.map(card => card._ref);
    client.fetch(
      `*[_id in $ids]{ ..., theme-> }`,
      { ids: cardIds }
    ).then(setResolvedCards);
  }, [cards]);
  
  // Render using resolvedCards with theme.hex available
}

This is a known limitation mentioned in the Sanity community discussions, where complex nested references require manual resolution rather than relying on the select syntax.

The preview system is intentionally limited to prevent performance issues from deeply nested queries running every time a document list renders. For arrays of references, manual resolution gives you more control over when and how the data is fetched.

Hope this helps! 🚀

Preview use a weird syntax that doesn’t translate to GROQ in some cases. Notably, you won’t use square brackets and I think you can treat them as if they’re dereferenced. Can you try changing theme (in your select) to:

theme: 'cards.0.theme.hex'
Or maybe (I don’t know your schema):


theme: 'cards.0.hex'
Previews use a weird syntax that doesn’t translate to GROQ in some cases. Notably, you won’t use square brackets and I think you can treat them as if they’re dereferenced. Can you try changing theme (in your select) to:

theme: 'cards.0.theme.hex'
Or maybe (I don’t know your schema):


theme: 'cards.0.hex'
theme: 'cards.0.theme.hex
worked ✨Is it possible to get all array items of cards?
Great!
Unfortunately, no. You’d need to request them individually, getting as many as you need in the `select`:


theme0: 'cards.0.theme.hex
theme1: 'cards.1.theme.hex
theme2: 'cards.2.theme.hex
theme3: 'cards.3.theme.hex
And then managing those in your
prepare
function.
Ok, I see. Thanks for the quick answer
Once you do them manually like that, the main 'cards' should contain them all. Weird quirk. I've dug into the sanity logic a few times trying to 'fix' this and it is annoying but I haven't solved it yet.

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?