Previewing content in Sanity Studio
When editing content, itβs very useful for content creators to be able to preview how their changes will appear before publishing.
There are different approaches to previewing unpublished content depending on your use case, the technology you're building with, and how complex your content models are.
With Sanity Studio, you can accommodate previews' in several ways:
- Generate a link in the user interface to an external preview or production environment withΒ
document.productionUrl
Β in the Studio configuration - Build custom side-by-side previews by customizing the document view withΒ Structure Builder
- Embed a frontend presentation tailored for previews in a document view usingΒ the Iframe Pane plugin, or a custom view component.
Previewing in your application or experience
This article mainly covers how to preview content within the studio, but is related to the topic of how to create front end previews of your content in general. To learn more about how you can use Content Lakeβs Perspectives feature to selectively retrieve content as if all your drafts were published, or as if no drafts existed, please see the Presenting and Previewing Content article.
You can generate a link to a front end preview environment that will appear behind the three-dotted menu above the document view.
This is done by returning a URL viaΒ document.productionUrl
Β where you configure your Studio, typically inΒ sanity.config.ts
. This property accepts a callback function that is invoked with any previousΒ productionUrl
Β values as the first argument, andΒ context
Β as it second, with useful values like the currentΒ document
Β state,Β projectId
,Β dataset
,Β currentUser
, a configuredΒ client
Β for fetching referenced documents, and the Studio'sΒ schema
.
You can also return a promise in case you want to fetch information from other documents or an external source to generate the URL.
// sanity.config.ts
import {defineConfig} from 'sanity'
import {deskTool} from 'sanity/desk'
export default defineConfig({
name: 'default',
title: 'My Cool Project',
projectId: 'my-project-id',
dataset: 'production',
document: {
// prev is the result from previous plugins and thus can be composed
productionUrl: async (prev, context) => {
// context includes the client and other details
const {getClient, dataset, document} = context
const client = getClient({apiVersion: '2023-05-31'})
if (document._type === 'post') {
const slug = await client.fetch(
`*[_type == 'routeInfo' && post._ref == $postId][0].slug.current`,
{postId: document._id}
)
const params = new URLSearchParams()
params.set('preview', 'true')
params.set('dataset', dataset)
return `https://my-site.com/posts/${slug}?${params}`
}
return prev
},
},
})
Gotcha
Sanity Studio currently supports only one generated link. You can come into situations where plugins implement their own productionUrl
setting. Depending on how you deal with the prev
value, your customization might override that of a plugin.
You might have seen theΒ Preview Anything blog postΒ that features different types of previews beyond the visual representation of a website. It shows how you can preview how content appears in Search Engine Result Pages, social media, in different accessibility accommodations, and specialized renders of signage and physical publishing.
While you can use theΒ document.productionUrl
Β in the Studio configuration to generate helpful links for content creators, another approach is to add custom views to the document pane in the Studio. This is powerful, especially when you have support for real-time content previews.
You can add additional document views using theΒ Structure Builder API. While you can add views to any document node when you define document list trees, the quickest way to add views is by usingΒ the Desk toolβs defaultDocumentNode propertyΒ to return document views conditionally on a documentβs value (for example, itsΒ _type
).
A documentΒ view
Β takes any React component that receives document values for its different states in real-time (draft
,Β displayed
,Β historical
,Β published
) in props. You can use this with custom components to build previews or embed a remote preview web page in anΒ <iframe>
. If you want to do the latter, we recommend checking outΒ the Iframe pane plugin available on sanity.io/exchange. Below is an example of how to implement it:
// sanity.config.ts
import {defineConfig} from 'sanity'
import {deskTool, type DefaultDocumentNodeResolver} from 'sanity/desk'
import Iframe from 'sanity-plugin-iframe-pane'
import {SanityDocument} from 'sanity'
// Customize this function to show the correct URL based on the current document
function getPreviewUrl(doc: SanityDocument) {
return doc?.slug?.current
? `${window.location.host}/${doc.slug.current}`
: window.location.host
}
const defaultDocumentNode: DefaultDocumentNodeResolver = (S, {schemaType}) => {
// Only show preview pane on `movie` schema type documents
switch (schemaType) {
case `movie`:
return S.document().views([
S.view.form(),
S.view
.component(Iframe)
.options({
url: (doc: SanityDocument) => getPreviewUrl(doc),
})
.title('Preview'),
])
default:
return S.document().views([S.view.form()])
}
}
export default defineConfig({
// ...other config settings
plugins: [
deskTool({
defaultDocumentNode,
}),
// ...other plugins
],
})
Sometimes you might not need drafts at all. Say you're using listeners to update a ranking list in an app and you just want the changes in the studio to go out in real-time on the wire as mutations as the order is being changed.
To disable drafts for a data type simply includeΒ liveEdit: true
Β in the schema definition, for example:
export default {
name: 'author',
title: 'Author',
type: 'document',
liveEdit: true,
β¦
}