
Grab your gear: The official Sanity swag store
Read Grab your gear: The official Sanity swag storeGreat question! While that v2 schema example is a bit dated, the good news is that migrating it to v3 is pretty straightforward once you understand the key differences. Let me walk you through what's changed and point you to some helpful resources.
The main changes for custom input components in Studio v3 are:
inputComponent, you now use components.input in your field definitionPatchEvent is now just using set() and unset() from sanity)Here's the basic structure you'll need. First, your schema definition:
{
name: 'vimeoVideo',
type: 'string',
title: 'Vimeo Video',
components: {
input: VimeoPreviewInput // This is the v3 way
}
}And here's a basic v3 custom input component to get you started:
import { set, unset } from 'sanity'
import { Stack, TextInput, Card } from '@sanity/ui'
import { useCallback, useState, useEffect } from 'react'
export function VimeoPreviewInput(props) {
const { value, onChange, elementProps } = props
const [thumbnailUrl, setThumbnailUrl] = useState(null)
// Extract Vimeo ID from URL or use raw ID
const getVimeoId = (input) => {
if (!input) return null
const match = input.match(/vimeo\.com\/(\d+)/)
return match ? match[1] : input
}
const vimeoId = getVimeoId(value)
// Fetch Vimeo thumbnail
useEffect(() => {
if (vimeoId) {
fetch(`https://vimeo.com/api/v2/video/${vimeoId}.json`)
.then(res => res.json())
.then(data => setThumbnailUrl(data[0]?.thumbnail_large))
.catch(() => setThumbnailUrl(null))
}
}, [vimeoId])
const handleChange = useCallback((event) => {
const inputValue = event.currentTarget.value
onChange(inputValue ? set(inputValue) : unset())
}, [onChange])
return (
<Stack space={3}>
<TextInput
{...elementProps}
value={value || ''}
onChange={handleChange}
placeholder="Enter Vimeo ID or URL"
/>
{thumbnailUrl && (
<Card padding={2} border>
<img
src={thumbnailUrl}
alt="Vimeo preview"
style={{ width: '100%', height: 'auto' }}
/>
</Card>
)}
</Stack>
)
}I'd highly recommend checking out this guide on creating your first input component for Studio v3 - it walks through all the fundamentals with practical examples.
The official form components documentation is also super helpful for understanding all the props your component receives and best practices.
set() and unset() from the sanity package for your onChange patcheselementProps should be spread onto your input element for proper accessibility and focus management@sanity/ui (like Stack, Card, TextInput) to maintain visual consistency with StudioSince you mentioned you're a React novice, the pattern is basically: your component receives value and onChange as props (just like a controlled React component), and you call onChange(set(newValue)) whenever the user makes a change. The Vimeo API part is just a standard useEffect + fetch pattern.
Hope this helps get you started! Feel free to ask if you run into any specific issues while building it out. 🙏
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