Convert comma-separated string to multiple tag references in Sanity array

12 repliesLast updated: Dec 2, 2025

Hello, I’m new to Sanity, I’ve created a Tag type that includes a slug and a title, then in the Post type I’ve added this field:

{
      name: 'tags',
      title: 'Tags',
      type: 'array',
      of: [{type: 'reference', to: {type: 'tag'}}]
    }
It works but I have to add / select tags one by one, is there any way to convert a comma-separated string to multiple tags (they are objects and it’s not a string array).

Thanks
AI Update

Great question! Yes, you can definitely create a better UX for adding multiple tags at once. You'll need to build a custom input component that accepts comma-separated input and converts it to tag references.

Here's a working approach:

import {set, unset, insert, setIfMissing} from 'sanity'
import {Stack, TextInput, Button, Card, Text, Flex} from '@sanity/ui'
import {useCallback, useState} from 'react'
import {useClient} from 'sanity'

function TagsInput(props) {
  const {value = [], onChange, schemaType} = props
  const [inputValue, setInputValue] = useState('')
  const client = useClient({apiVersion: '2023-01-01'})
  
  const handleAddTags = useCallback(async () => {
    // Split by comma and clean up
    const tagNames = inputValue
      .split(',')
      .map(t => t.trim())
      .filter(Boolean)
    
    if (tagNames.length === 0) return
    
    // Create or fetch tag documents
    const tagRefs = await Promise.all(
      tagNames.map(async (tagName) => {
        const slug = tagName.toLowerCase().replace(/\s+/g, '-')
        
        // Check if tag already exists
        const existingTag = await client.fetch(
          `*[_type == "tag" && slug.current == $slug][0]`,
          {slug}
        )
        
        if (existingTag) {
          return {
            _type: 'reference',
            _ref: existingTag._id,
            _key: `tag-${Date.now()}-${Math.random()}`
          }
        }
        
        // Create new tag document
        const newTag = await client.create({
          _type: 'tag',
          title: tagName,
          slug: {_type: 'slug', current: slug}
        })
        
        return {
          _type: 'reference',
          _ref: newTag._id,
          _key: `tag-${Date.now()}-${Math.random()}`
        }
      })
    )
    
    // Merge with existing tags
    const newValue = [...(value || []), ...tagRefs]
    onChange(set(newValue))
    setInputValue('')
  }, [inputValue, value, onChange, client])
  
  return (
    <Stack space={3}>
      <Flex gap={2}>
        <Card flex={1}>
          <TextInput
            value={inputValue}
            onChange={(e) => setInputValue(e.currentTarget.value)}
            placeholder="Enter tags separated by commas"
            onKeyDown={(e) => {
              if (e.key === 'Enter') {
                e.preventDefault()
                handleAddTags()
              }
            }}
          />
        </Card>
        <Button onClick={handleAddTags} text="Add Tags" tone="primary" />
      </Flex>
      
      {value && value.length > 0 && (
        <Text size={1} muted>
          {value.length} tag{value.length !== 1 ? 's' : ''} selected
        </Text>
      )}
      
      {/* Render the default array input below */}
      {props.renderDefault(props)}
    </Stack>
  )
}

// In your schema:
export default {
  name: 'post',
  type: 'document',
  fields: [
    {
      name: 'tags',
      title: 'Tags',
      type: 'array',
      of: [{type: 'reference', to: {type: 'tag'}}],
      components: {
        input: TagsInput
      }
    }
  ]
}

How this works:

Key points:

This gives you the best of both worlds - quick bulk tag entry while keeping your clean reference-based data structure intact!

Show original thread
12 replies

Was this answer helpful?

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.

Related contributions