Add custom text input option to predefined options list in Sanity Studio
I 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:
- The component uses Sanity's PatchEvent system with
set()andunset()to properly update the field value - It uses components from
@sanity/uito maintain visual consistency with the rest of Studio - The value is still stored as a simple string, so it works seamlessly with queries and validation
- You can enhance this with validation to ensure custom values meet your requirements
If 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.
Show original thread6 replies
Sanity – Build the way you think, not the way your CMS thinks
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.