Slug Generating Document Action - How to Invalidate Fields or Display an Error

14 replies
Last updated: Mar 13, 2021
I am improving my
slug
generating document action, which replaces the default publish action. Can someone help me understand what my options are for invalidating fields or displaying an error, and then aborting a publish from within my custom publish action? Is there a place in the documentation where I may have missed this? Thanks!
AI Update

When working with custom document actions in Sanity Studio, you have several options for handling validation, showing errors, and aborting the publish action. Here's what you can do:

Aborting a Publish Action

To abort a publish action, you control the flow in your custom action's onHandle method. The key is to not call the publish operation's execute() method when you want to abort:

import {useDocumentOperation} from 'sanity'
import {useToast} from '@sanity/ui'

export function CustomPublishAction(props) {
  const {patch, publish} = useDocumentOperation(props.id, props.type)
  const toast = useToast()

  return {
    disabled: publish.disabled,
    label: 'Publish',
    onHandle: () => {
      // Validate your conditions
      if (!props.draft?.slug?.current) {
        // Show error and abort
        toast.push({
          status: 'error',
          title: 'Cannot publish',
          description: 'Document must have a slug before publishing'
        })
        // Don't call publish.execute() - this aborts the action
        props.onComplete()
        return
      }
      
      // If validation passes, proceed with publish
      publish.execute()
      props.onComplete()
    }
  }
}

Showing Errors and User Feedback

You have multiple ways to display errors:

The useToast hook from @sanity/ui is the standard way to show feedback:

import {useToast} from '@sanity/ui'

const toast = useToast()

toast.push({
  status: 'error', // 'success', 'warning', 'info'
  title: 'Error title',
  description: 'Detailed error message'
})

2. Using Dialogs

For more complex validation that requires user interaction, you can use the dialog property as shown in the document actions documentation:

const [showDialog, setShowDialog] = useState(false)

return {
  label: 'Publish',
  onHandle: () => {
    if (hasValidationErrors) {
      setShowDialog(true)
      return // Abort the publish
    }
    publish.execute()
  },
  dialog: showDialog && {
    type: 'dialog',
    header: 'Validation Error',
    content: <div>Your custom error message and UI here</div>,
    onClose: () => setShowDialog(false)
  }
}

Leveraging Built-in Validation

You can also use Sanity's built-in validation system by checking the document's validation status:

import {useValidationStatus} from 'sanity'

export function CustomPublishAction(props) {
  const {validation} = useValidationStatus(props.id, props.type)
  const hasErrors = validation.some(item => item.level === 'error')

  return {
    disabled: publish.disabled || hasErrors,
    label: 'Publish',
    onHandle: () => {
      if (hasErrors) {
        toast.push({
          status: 'error',
          title: 'Cannot publish',
          description: 'Please fix validation errors first'
        })
        props.onComplete()
        return
      }
      publish.execute()
      props.onComplete()
    }
  }
}

Key Points

  • Always call props.onComplete() when your action finishes, whether it succeeds or aborts
  • Don't call execute() on the operation if you want to abort
  • The disabled property can prevent the action from being triggered at all
  • Toast notifications are the most user-friendly way to show errors
  • You can combine multiple validation approaches for robust error handling

The complete reference is available in the Document Actions documentation and Document Actions API reference.

Does this help? https://www.sanity.io/docs/validation#fcadf15930b3 looks like validation isn't very feature rich at the moment. There is a validateDocument function in sanity if you search GitHub though.
user L
, I don't think that helps, unfortunately.
I am trying to ensure that the slug I am setting will be unique and I am doing that within the publish action. I would expect there to be a way to "cancel" or "abort" the publish action.
So your slug has a unique validation on it and when you patch it the document still gets saved?
user L
in my document action, I can choose to publish the document or not. I'm choosing not to, when the slug is not unique. It is at that point that I'd like to send a message to the UI stating why the document cannot be published.
If you throw an error does it appear in a red box near the publish button? somehow the intl-input plugin does it when the doc references another one like that.
This enforced document linking and shows an error after the attempted action https://github.com/LiamMartens/sanity-plugin-intl-input
I will look into that plugin, if I throw an error I see it in the console but not in a popup of any kind.
Ah ok. Wonder if you need to push to the toast module in sanity?
Ill try it out myself on Monday as I'm interested now.
hmmm. I like the idea of using a toast. I just don't know how to get access to the
toast
object to push a new message to. Maybe I'm misunderstanding the docs.
Should be able to use the hook and call it.
Got it, thanks again
user L
!
import {useToast} from '@sanity/ui'
...

const toast = useToast()
...

toast.push({status:'error', title: error})

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.

Was this answer helpful?