How AI is powering better personalization in e-commerce [with Vercel]. Sign up now

Auto-generate readOnly/hidden field value from another field in Sanity

12 repliesLast updated: Dec 1, 2025

Is there a way to automatically set a readOnly or hidden field? I was hoping that I could create a slug field that would be generated from a number field using the
source
and
slufigy
options but it doesn't get created automatically set to a value upon publish.
AI Update

The slug field's source and slugify options don't automatically generate the slug value on publish - they only power the "Generate" button in the Studio UI. However, you can automatically set a slug (or any readOnly/hidden field) on publish using a custom document action.

Here's the correct way to implement this in Studio v3:

Create a Custom Publish Action

First, create your custom action component (e.g., actions/SetSlugAndPublish.tsx):

import { useDocumentOperation } from 'sanity'
import { useState, useEffect } from 'react'
import type { DocumentActionComponent } from 'sanity'

function generateSlug(text: string | number): string {
  return String(text)
    .toLowerCase()
    .replace(/\s+/g, '-')
    .replace(/[^\w-]+/g, '')
}

export const SetSlugAndPublishAction: DocumentActionComponent = (props) => {
  const { patch, publish } = useDocumentOperation(props.id, props.type)
  const [isPublishing, setIsPublishing] = useState(false)

  useEffect(() => {
    // Reset publishing state if publish completes
    if (isPublishing && !publish.disabled) {
      setIsPublishing(false)
    }
  }, [isPublishing, publish.disabled])

  return {
    label: isPublishing ? 'Publishing...' : 'Publish',
    disabled: publish.disabled || isPublishing,
    onHandle: () => {
      setIsPublishing(true)
      
      // Generate slug from your source field(s)
      // For a number field:
      const slug = generateSlug(props.draft?.yourNumberField || '')
      
      // Patch the document with the slug
      patch.execute([{ set: { slug: { _type: 'slug', current: slug } } }])
      
      // Then publish
      publish.execute()
      
      props.onComplete()
    }
  }
}

Register the Action in Your Config

In your sanity.config.ts (or .js):

import { defineConfig } from 'sanity'
import { SetSlugAndPublishAction } from './actions/SetSlugAndPublish'

export default defineConfig({
  // ... other config
  document: {
    actions: (prev, context) => {
      // Replace the default publish action for specific document types
      if (context.schemaType === 'yourDocumentType') {
        return prev.map((originalAction) => 
          originalAction.action === 'publish' 
            ? SetSlugAndPublishAction 
            : originalAction
        )
      }
      return prev
    }
  }
})

Key Points for Studio v3

Important differences from older patterns:

Alternative: Using Initial Value Templates

If you want the slug set when the document is created (not on publish), you can use Initial Value Templates instead:

import { defineConfig } from 'sanity'

export default defineConfig({
  // ... other config
  schema: {
    templates: (prev) => [
      ...prev,
      {
        id: 'document-with-slug',
        title: 'Document with Slug',
        schemaType: 'yourDocumentType',
        value: (params) => ({
          slug: {
            _type: 'slug',
            current: generateSlug(params.yourNumberField || 'default')
          }
        })
      }
    ]
  }
})

This approach works great for hidden or readOnly fields that should be set automatically based on other field values when publishing or creating documents.

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