Change `tags` layout to be an autocomplete kind of deal.
Great question! You'll want to create a custom input component that replaces the default array string input with an autocomplete experience. Here's how to approach this:
The Solution
You need to build a custom input component that uses the Sanity UI Autocomplete component and queries existing tags from your content. Here's the basic structure:
import {set, unset} from 'sanity'
import {Autocomplete, Card} from '@sanity/ui'
import {useCallback, useState, useEffect} from 'react'
import {useClient} from 'sanity'
function TagsAutocompleteInput(props) {
const {onChange, value = [], schemaType} = props
const [inputValue, setInputValue] = useState('')
const [existingTags, setExistingTags] = useState([])
const client = useClient({apiVersion: '2024-01-01'})
// Fetch existing tags from your content
useEffect(() => {
client.fetch(`array::unique(*[defined(tags)].tags[])`)
.then(setExistingTags)
}, [client])
// Filter tags based on input
const suggestions = existingTags.filter(tag =>
tag.toLowerCase().startsWith(inputValue.toLowerCase())
)
const handleSelect = useCallback((selectedTag) => {
// Add the selected tag to the array
const newValue = [...(value || []), selectedTag]
onChange(set(newValue))
setInputValue('') // Clear input for next tag
}, [value, onChange])
const handleRemoveTag = useCallback((index) => {
const newValue = value.filter((_, i) => i !== index)
onChange(newValue.length ? set(newValue) : unset())
}, [value, onChange])
return (
<Card>
{/* Display existing tags with remove buttons */}
<div>
{value?.map((tag, index) => (
<span key={index}>
{tag}
<button onClick={() => handleRemoveTag(index)}>Γ</button>
</span>
))}
</div>
{/* Autocomplete input */}
<Autocomplete
options={suggestions.map(tag => ({value: tag}))}
value={inputValue}
onChange={setInputValue}
onSelect={handleSelect}
placeholder="Type to search tags..."
/>
</Card>
)
}Integrate it into your schema
Modify your field definition to use the custom component:
{
name: 'tags',
title: 'Tags',
type: 'array',
of: [{type: 'string'}],
components: {
input: TagsAutocompleteInput
},
validation: Rule => Rule.required().min(2).error('At least 2 tags are required.')
}Fetching Existing Tags
The GROQ query array::unique(*[defined(tags)].tags[]) flattens all tag arrays across your documents and returns unique values - perfect for your autocomplete suggestions!
Key Points
- Custom input components receive
value,onChange, and other props to integrate with Studio's form system - Use
set()andunset()from thesanitypackage to patch changes back to the Content Lake - The Sanity UI Autocomplete component handles the dropdown UI and keyboard navigation for you
- You can wrap your component with
FormFieldfromsanityif you want to preserve the label, description, and validation UI around your custom input
Check out the custom input component guide for more detailed examples and best practices. The guide walks through all the props available and how to properly handle patch events!
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.