
Grab your gear: The official Sanity swag store
Read Grab your gear: The official Sanity swag storeThe issue you're experiencing is a common one when working with references in Portable Text. When you query Portable Text that contains custom blocks with references, you only get the _ref ID, not the actual document data. The solution is to dereference the reference in your GROQ query using special syntax for nested arrays.
Since your reference is inside a custom block within your Portable Text array, you need to use GROQ's dereferencing operator (->) combined with array projection syntax.
In your GROQ query where you fetch the Portable Text content, you need to explicitly dereference the reference:
*[_type == "post"][0] {
title,
content[]{
...,
// For your custom video block
_type == "videoBlock" => {
...,
"video": videoReference->{
_id,
title,
"playbackId": asset->playbackId,
"assetId": asset->assetId,
// any other Mux fields you need
}
}
}
}The key parts here are:
videoReference-> - The -> operator dereferences the reference and fetches the referenced documentasset->playbackId to get nested reference data_type == "videoBlock" =>) to only apply it to your specific block typeIf your video reference is actually an annotation rather than a block, the syntax is slightly different because it's nested inside the markDefs array:
content[]{
...,
markDefs[]{
...,
_type == "videoReference" => {
...,
"videoData": @.reference->{
_id,
title,
"playbackId": asset->playbackId,
"assetId": asset->assetId
}
}
}
}The @ symbol refers to the current item in the array context, which is necessary when working with nested arrays like markDefs.
Once you've dereferenced in the query, your serializer will receive the full data:
import { PortableText } from '@portabletext/react'
const components = {
types: {
videoBlock: ({value}) => {
// Now value.video contains all the fields you queried
const { playbackId, title } = value.video
return (
<div>
<h3>{title}</h3>
<MuxPlayer playbackId={playbackId} />
</div>
)
}
}
}
// Usage
<PortableText value={content} components={components} />This approach ensures you get all the referenced document data in a single query, avoiding the need to fetch it separately in your render function. The dereferencing happens at query time, so your serializer receives complete data objects rather than just reference IDs.
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.
Content operations
Content backend


The only platform powering content operations
By Industry


Tecovas strengthens their customer connections
Build and Share

Grab your gear: The official Sanity swag store
Read Grab your gear: The official Sanity swag store