
Grab your gear: The official Sanity swag store
Read Grab your gear: The official Sanity swag storeI need to create a custom input component for this use case. While Sanity's string type with an options list gives you predefined choices, there's no built-in feature to automatically add a "custom text input" option to that list. The solution is to create a custom input component.
Here's how you can build this:
import { set, unset } from 'sanity'
import { Stack, Select, TextInput, Card, Text } from '@sanity/ui'
import { useState } from 'react'
const presetLabels = ['First Name', 'Last Name', 'Company', 'Email', 'Message', 'Phone']
function LabelInput(props) {
const { value, onChange } = props
const [useCustom, setUseCustom] = useState(
value && !presetLabels.includes(value)
)
const handlePresetChange = (event) => {
const newValue = event.currentTarget.value
if (newValue === '__custom__') {
setUseCustom(true)
onChange(unset())
} else {
setUseCustom(false)
onChange(newValue ? set(newValue) : unset())
}
}
const handleCustomChange = (event) => {
const newValue = event.currentTarget.value
onChange(newValue ? set(newValue) : unset())
}
return (
<Stack space={3}>
<Select
value={useCustom ? '__custom__' : (value || '')}
onChange={handlePresetChange}
>
<option value="">Select a label...</option>
{presetLabels.map((label) => (
<option key={label} value={label}>
{label}
</option>
))}
<option value="__custom__">Custom label...</option>
</Select>
{useCustom && (
<Card border padding={3}>
<Stack space={2}>
<Text size={1} weight="semibold">Custom Label</Text>
<TextInput
value={value || ''}
onChange={handleCustomChange}
placeholder="Enter custom label"
/>
</Stack>
</Card>
)}
</Stack>
)
}
// In your schema:
export default {
name: 'myDocument',
type: 'document',
fields: [
{
name: 'label',
title: 'Label',
type: 'string',
components: {
input: LabelInput
}
}
]
}This component gives users a dropdown with all your preset options plus a "Custom label..." option. When they select "Custom label...", a text input appears where they can type their own value.
Key points about this approach:
set() and unset() to properly update the field value@sanity/ui to maintain visual consistency with the rest of StudioIf you want a simpler UI, you could also just show the dropdown and text input side-by-side, or use radio buttons for presets with an "Other" option that reveals the text input. The custom input component approach gives you complete control over the UX.
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