
Grab your gear: The official Sanity swag store
Read Grab your gear: The official Sanity swag storeFor implementing a split pane preview in Sanity Studio with resolved references, you'll want to use a combination of custom Component Views and GROQ queries with the reference operator (->). Let me walk you through the best approach.
SanityDocument is a TypeScript type that represents any document in your Sanity Content Lake. When you run sanity typegen generate, it creates type definitions for all your schema types. The base SanityDocument type typically includes core fields like _id, _type, _createdAt, _updatedAt, and _rev.
If you're seeing SanityDocument in sanity-plugin-utils but can't figure out what it is, it's likely a generic type parameter. You'll want to use your own generated types from sanity typegen instead.
Here's the recommended approach using Component Views:
import { StructureBuilder as S } from 'sanity/structure'
import PreviewPane from './components/PreviewPane'
export const structure = (S) =>
S.list()
.title('Content')
.items([
S.listItem()
.title('Your Document Type')
.child(
S.documentTypeList('yourDocType')
.child((documentId) =>
S.document()
.documentId(documentId)
.schemaType('yourDocType')
.views([
S.view.form(),
S.view.component(PreviewPane).title('Preview')
])
)
)
])In your PreviewPane component, use the useClient hook to fetch the document with references resolved using GROQ's reference operator (->):
import { useEffect, useState } from 'react'
import { useClient } from 'sanity'
export default function PreviewPane(props) {
const { document } = props
const client = useClient({ apiVersion: '2024-01-01' })
const [resolvedDoc, setResolvedDoc] = useState(null)
useEffect(() => {
const query = `*[_id == $id][0]{
...,
// Resolve single reference
author->,
// Resolve array of references
categories[]->,
// Resolve nested references with specific fields
relatedPosts[]->{
title,
slug,
author->
}
}`
client.fetch(query, { id: document.displayed._id })
.then(setResolvedDoc)
}, [document.displayed._id, client])
if (!resolvedDoc) return <div>Loading preview...</div>
return (
<div style={{ padding: '2rem' }}>
<h2>{resolvedDoc.title}</h2>
<p>Author: {resolvedDoc.author?.name}</p>
{/* Render your preview with resolved data */}
</div>
)
}For a more robust solution that updates in real-time as you edit, you can use the client's listen() method:
useEffect(() => {
const query = `*[_id == $id][0]{ ..., author->, categories[]-> }`
const subscription = client.listen(query, { id: document.displayed._id })
.subscribe((update) => {
if (update.result) {
setResolvedDoc(update.result)
}
})
// Initial fetch
client.fetch(query, { id: document.displayed._id })
.then(setResolvedDoc)
return () => subscription.unsubscribe()
}, [document.displayed._id, client])The -> operator is powerful for resolving references in GROQ:
author-> resolves to the full author documentcategories[]-> resolves all category referencesauthor->{name, bio} gets only specific fieldsrelatedPosts[]->{ title, author-> } resolves multiple levelsKeep in mind that each -> performs a subquery internally, so be mindful of performance when resolving deeply nested or large arrays of references.
If you want full type safety, generate types with sanity typegen:
npx sanity@latest schema extract
npx sanity@latest typegen generateThen import and use your generated types:
import type { YourDocType } from './sanity.types'
const [resolvedDoc, setResolvedDoc] = useState<YourDocType | null>(null)This approach gives you a clean split pane view with fully resolved references, updating in real-time as you edit your document.
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