How to use references as block types in Sanity portable text
Yes, it is absolutely possible to set references as a block type for Portable Text! Your schema code looks correct. Let me explain how to work with it and query the referenced data.
Adding References to Portable Text
Your schema setup is valid:
defineField({
name: 'content',
type: 'array',
of: [
{ type: 'block' },
{
type: 'reference',
to: [{ type: 'reputation' }],
},
],
})This creates block-level references (as opposed to inline references or annotations). They'll appear as separate blocks in your Portable Text array.
Querying and Joining References in GROQ
To join (dereference) the reference in your GROQ query, you need to use the dereference operator ->:
*[_type == "yourDocType"][0] {
content[]{
...,
// For reference blocks, dereference them
_type == "reference" => @-> {
_id,
_type,
// Add the fields you need from the reputation document
title,
score,
// etc.
}
}
}Alternative Pattern
You can also be more explicit about handling different block types:
*[_type == "yourDocType"][0] {
content[]{
_type == "block" => @,
_type == "reference" => {
"_key": ^._key,
"_type": "reference",
"reputationData": @-> {
_id,
title,
score
}
}
}
}Rendering in Your Frontend
When using @portabletext/react, you'll need to add a custom serializer for the reference type:
import { PortableText } from '@portabletext/react'
const components = {
types: {
reference: ({value}) => {
// value will contain the dereferenced data if you queried it correctly
return (
<div className="reputation-reference">
<h3>{value.title}</h3>
<p>Score: {value.score}</p>
</div>
)
}
}
}
<PortableText value={content} components={components} />Key Points
Block-level vs Inline: Your current setup creates block-level references (separate blocks). If you want inline references within text, you'd add them to
marks.annotationsinstead.Dereferencing: The
->operator in GROQ fetches the referenced document's data. Without it, you'll only get{_ref: "id", _type: "reference"}.Array handling: Since references are inside the
contentarray, you need to handle them within the array projectioncontent[]{}.
Your approach is correct! Just make sure to dereference the data in your GROQ query and add appropriate serializers in your frontend rendering.
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.