
Grab your gear: The official Sanity swag store
Read Grab your gear: The official Sanity swag storeThis is a common challenge! Here are several approaches you can use to handle empty content gracefully in your previews:
The most straightforward approach is using the preview configuration in your schema with a prepare function that handles empty states:
export default {
name: 'myModule',
type: 'object',
fields: [
{name: 'title', type: 'string'},
{name: 'image', type: 'image'},
{name: 'content', type: 'text'}
],
preview: {
select: {
title: 'title',
image: 'image',
content: 'content'
},
prepare({title, image, content}) {
return {
title: title || '⚠️ No title added',
subtitle: content || 'Click to add content',
media: image || () => '📝' // or import an icon from @sanity/icons
}
}
}
}You can even provide more helpful feedback:
prepare({title, image, content}) {
const missing = []
if (!title) missing.push('title')
if (!image) missing.push('image')
if (!content) missing.push('content')
return {
title: title || 'Incomplete module',
subtitle: missing.length ? `Missing: ${missing.join(', ')}` : 'Ready',
media: image
}
}Prevent empty content from being saved in the first place using validation rules:
{
name: 'image',
type: 'image',
validation: Rule => Rule.required().error('Please add an image')
},
{
name: 'content',
type: 'text',
validation: Rule => Rule.required().warning('Content is recommended')
}Always check for empty values in your actual preview/frontend code:
function ModuleComponent({ module }) {
if (!module?.image || !module?.content) {
return (
<div className="preview-placeholder">
<p>⚠️ This module needs content</p>
<ul>
{!module?.image && <li>Add an image</li>}
{!module?.content && <li>Add content</li>}
</ul>
</div>
)
}
return (
// your normal component
)
}Or use fallback values with optional chaining:
const imageUrl = module?.image?.asset?.url ?? '/placeholder-image.jpg'
const title = module?.title ?? 'Untitled'
const content = module?.content ?? 'No content yet'For more complex scenarios, you can create a custom input component that shows warnings directly in the editing interface:
const CustomModuleInput = (props) => {
const {title, image, content} = props.value || {}
const hasEmptyFields = !title || !image || !content
return (
<Stack space={3}>
{hasEmptyFields && (
<Card tone="caution" padding={3}>
<Text>⚠️ Please complete all fields for this module</Text>
</Card>
)}
{props.renderDefault(props)}
</Stack>
)
}
// In your schema:
{
name: 'myModule',
type: 'object',
components: {
input: CustomModuleInput
}
}The combination of preview configuration with fallbacks (for Studio UI) and defensive coding in your frontend (for actual preview rendering) usually works best. This way editors get clear feedback about what's missing, and your preview never breaks even if incomplete content slips through.
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