How to disable the "Save" button in a custom document action when there are errors in the input fields.

14 replies
Last updated: Oct 1, 2021
Hello, I'm trying to make a custom document action and I don't want the changes in the document to be saved if there are errors in the input fields (the publish button should be off till all errors are fixed by the user). I'm trying to figure it out by referring to this page in the docs https://www.sanity.io/docs/document-actions-api but no luck so far. Any help will be much appreciated.
AI Update

I understand you want to disable your custom document action button when there are validation errors in the document. Unfortunately, there isn't a straightforward built-in way to check validation status directly from within a document action component in the current version of Sanity Studio.

The challenge here is that document actions don't have direct access to the document's validation state through a dedicated hook or API. The Document Actions API provides access to document properties like draft, published, id, and type, but not validation markers.

Current Limitations

Validation in Sanity Studio operates at the schema/form level, not at the document action level. The validation system is designed to:

  • Show real-time feedback in form fields
  • Prevent publishing through the built-in Publish action when errors exist
  • Display validation markers in the document editor

However, custom document actions don't automatically inherit this validation-aware behavior.

Possible Workarounds

While there's no direct solution, here are some approaches you might consider:

1. Leverage the Built-in Publish Action

The simplest approach is to use Sanity's built-in PublishAction, which already handles validation automatically. If your custom action ultimately publishes the document, consider whether you really need a custom action or if you can extend the default behavior through other means like Initial Value Templates or document lifecycle hooks.

2. Implement Validation Logic Directly

If you need custom validation logic specific to your action, you can implement the validation checks directly within your action's onHandle function:

export function CustomAction(props) {
  const {patch, publish} = useDocumentOperation(props.id, props.type)
  const [isProcessing, setIsProcessing] = useState(false)

  return {
    label: 'Custom Save',
    disabled: publish.disabled, // Respects the same disabled state as publish
    onHandle: () => {
      // Perform your custom validation here
      const doc = props.draft || props.published
      
      if (!doc?.title || doc.title.length < 10) {
        // Show validation error
        alert('Title must be at least 10 characters')
        return
      }
      
      setIsProcessing(true)
      // Proceed with your custom logic
      patch.execute([/* your patches */])
      publish.execute()
      props.onComplete()
    }
  }
}

3. Check the disabled State of Publish

You can reference the disabled property from the publish operation returned by useDocumentOperation. While this doesn't give you granular validation details, it respects the same conditions that would disable the built-in publish button:

const {publish} = useDocumentOperation(props.id, props.type)

return {
  label: 'My Action',
  disabled: publish.disabled,
  // ... rest of action
}

Important Note About Validation

Remember that validation in Sanity is client-side only within the Studio. If you're performing operations through the API or need server-side validation, you'll need to implement those checks separately.

If this is a critical feature for your workflow, I'd recommend reaching out to the Sanity community Slack or filing a feature request, as access to validation state from document actions would be a valuable addition to the API.

Hi Amrita. It sounds like Validation should do the trick. 🙂
Thank you for your reply. I have used validation in the input fields which shows the errors correctly. I dont want to “Save” button to be activated when there are errors in the document (pls see attached screenshot)
This is my customSaveAction.js
import { useState, useEffect } from "react";
import { useDocumentOperation } from "@sanity/react-hooks";
export function SetAndSaveAction(props) {
  const { patch, publish } = useDocumentOperation(props.id, props.type);
  const [isPublishing, setIsPublishing] = useState(false);

  useEffect(() => {
    // if the isPublishing state was set to true and the draft has changed
    // to become `null` the document has been published
    if (isPublishing && !props.draft) {
      setIsPublishing(false);
    }
  }, [props.draft]);

  return {
    disabled: publish.disabled,
    label: isPublishing ? "Saving..." : "Save",
    onHandle: () => {
      // This will update the button text
      setIsPublishing(true);

      // Set publishedAt to current date and time
      patch.execute([{ set: { publishedAt: new Date().toISOString() } }]);

      // Perform the publish
      publish.execute();

      props.onComplete();
    },
  };
}
Thanks for that. What does your validation function look like in your schema?
{
            name: "internalLink",
            type: "object",
            title: "Internal Link",
            fields: [
              {
                name: "pageReference",
                type: "reference",
                validation: (Rule) =>
                  Rule.required().warning("Missing Internal Link"),
                to: [{ type: "page" }],
              },
            ],
          },
Thank you for your reply. I have used validation in the input fields which shows the errors correctly. I dont want to “Save” button to be activated when there are errors in the document (pls see attached screenshot)
Interesting. It seems to work (i.e., blocks publishing) when I gave this a try. I’ll try a few additional things tomorrow. In the meantime, what version of the studio are you working on? (Discoverable by running
sanity versions
in your terminal.)
@sanity/cli 2.18.0 (latest: 2.20.0)@sanity/base 2.20.0 (up to date)
@sanity/block-content-to-react 3.0.0 (up to date)
@sanity/client 2.19.0 (up to date)
@sanity/components 2.14.0 (up to date)
@sanity/core 2.20.0 (up to date)
@sanity/dashboard 2.20.0 (up to date)
@sanity/default-layout 2.20.0 (up to date)
@sanity/default-login 2.19.0 (up to date)
@sanity/desk-tool 2.20.0 (up to date)
@sanity/vision 2.20.0 (up to date)
@sanity/cli 2.18.0 (latest: 2.20.0)@sanity/base 2.20.0 (up to date)
@sanity/block-content-to-react 3.0.0 (up to date)
@sanity/client 2.19.0 (up to date)
@sanity/components 2.14.0 (up to date)
@sanity/core 2.20.0 (up to date)
@sanity/dashboard 2.20.0 (up to date)
@sanity/default-layout 2.20.0 (up to date)
@sanity/default-login 2.19.0 (up to date)
@sanity/desk-tool 2.20.0 (up to date)
@sanity/vision 2.20.0 (up to date)
Thanks for your help Geoff!
Thanks for your help Geoff!
Thanks! Sorry I have to leave this for now but if it’s not picked up by a colleague I’ll take another look tomorrow.
No worries. I’ll keep trying in the meanwhile.
I think I fixed it (although it feels like a hack). I checked if the document had any validation markers and if it did then disable the Save button.
import { useState, useEffect } from "react";
import { useDocumentOperation, useValidationStatus } from "@sanity/react-hooks";
export function SetAndSaveAction(props) {
  const { patch, publish } = useDocumentOperation(props.id, props.type);
  const { markers } = useValidationStatus(props.id, props.type);
  const [isPublishing, setIsPublishing] = useState(false);

  useEffect(() => {
    // if the isPublishing state was set to true and the draft has changed
    // to become `null` the document has been published
    if (isPublishing && !props.draft) {
      setIsPublishing(false);
    }
  }, [props.draft]);

  return {
    disabled: markers.length ? true : publish.disabled,
    label: isPublishing ? "Saving..." : "Save",
    onHandle: () => {
      // This will update the button text
      setIsPublishing(true);

      // Set publishedAt to current date and time
      patch.execute([{ set: { publishedAt: new Date().toISOString() } }]);

      // Perform the publish
      publish.execute();

      // Signal that the action is completed
      props.onComplete();
    },
  };
}

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?