
Grab your gear: The official Sanity swag store
Read Grab your gear: The official Sanity swag storeYou're absolutely right to be concerned about exposing auth tokens in client-side code! The good news is you don't need a proxy server for this use case. Your custom input component runs inside the authenticated Sanity Studio environment, which already handles authentication through the user's login session.
You shouldn't be using a separate sanityClient with auth tokens inside custom input components. The Studio already has authentication, and custom components communicate changes through the onChange prop that's passed to your component.
Your custom input component receives onChange and value props from Sanity. To make updates, you use the onChange callback with patch operations like set() and unset().
import {set, unset} from 'sanity'Note: In Studio v3, you import set and unset directly from 'sanity', not from @sanity/form-builder (that was Studio v2). There's no separate PatchEvent class in v3 - you just pass the patch operations directly to onChange.
export function SectionItemList(props) {
const {onChange, value = []} = props
// In v3, onChange accepts patch operations directly
const handleChange = (newValue) => {
onChange(newValue ? set(newValue) : unset())
}
}To update fields within a specific array item, you work with the entire value array:
const updateLabel = (key, newLabel) => {
const updatedSections = value.map(section =>
section._key === key
? {...section, label: newLabel}
: section
)
onChange(set(updatedSections))
}
const updateStartTime = (key, newTime) => {
const updatedSections = value.map(section =>
section._key === key
? {...section, startTime: newTime}
: section
)
onChange(set(updatedSections))
}To add a new item, generate a unique _key for it:
import {randomKey} from '@sanity/util/content'
const addNewWorkoutGroup = () => {
const newGroup = {
_type: 'workoutgroup',
_key: randomKey(12),
label: 'New Workout',
startTime: '',
exercises: []
}
const updatedSections = [...value, newGroup]
onChange(set(updatedSections))
}For nested arrays, you update the parent array with the modified nested structure:
// Update entire exercises array for a specific workout group
const updateExercises = (workoutGroupKey, newExercises) => {
const updatedSections = value.map(section =>
section._key === workoutGroupKey
? {...section, exercises: newExercises}
: section
)
onChange(set(updatedSections))
}
// Add a single exercise to a workout group
const addExercise = (workoutGroupKey, newExercise) => {
const exerciseWithKey = {
...newExercise,
_key: randomKey(12),
_type: 'workoutgroupexercise'
}
const updatedSections = value.map(section =>
section._key === workoutGroupKey
? {
...section,
exercises: [...(section.exercises || []), exerciseWithKey]
}
: section
)
onChange(set(updatedSections))
}const removeWorkoutGroup = (key) => {
const updatedSections = value.filter(section => section._key !== key)
onChange(
updatedSections.length > 0
? set(updatedSections)
: unset()
)
}Your schema should use the components.input property for Studio v3:
{
name: 'sections',
title: 'Sections',
type: 'array',
components: {
input: SectionItemList // Studio v3 syntax
},
of: [
{
type: 'workoutgroup',
weak: true,
},
],
}Note: If you were using inputComponent (camelCase), that was Studio v2 syntax. Studio v3 uses the components object.
Your proxy server idea would technically work, but it's unnecessary complexity that would:
The onChange pattern is the standard approach for custom input components and keeps everything secure within the authenticated Studio environment. Your custom component has full access to make changes through onChange without needing any additional authentication.
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