How to create a new document in draft mode using Sanity.js and Next.js.

4 replies
Last updated: Mar 26, 2024
Hey, Im trying learn something new. Let a user submit a form in the front-end, this should create a new document in draft mode, does anyone have an example of this being done?
AI Update

Absolutely! Creating a document from a frontend form and saving it as a draft is a common pattern. Here's what you need to know:

The Key Concept: Prepend drafts. to the Document ID

When you create a document through the Sanity Client, you can make it a draft by prepending drafts. to the document's _id. This is exactly how Sanity Studio handles drafts internally.

Basic Example

Here's a simple example of how to do this:

import { createClient } from '@sanity/client'

const client = createClient({
  projectId: 'your-project-id',
  dataset: 'your-dataset',
  useCdn: false, // We need fresh data when writing
  token: 'your-write-token', // You'll need a token with write permissions
  apiVersion: '2024-03-01'
})

// Handle form submission
async function handleFormSubmit(formData) {
  const newDocument = {
    _id: `drafts.${Date.now()}`, // Prepend 'drafts.' to create a draft
    _type: 'yourDocumentType',
    title: formData.title,
    // ... other fields from your form
  }

  try {
    const result = await client.create(newDocument)
    console.log('Draft created:', result)
  } catch (error) {
    console.error('Error creating draft:', error)
  }
}

Important Considerations

Authentication: You'll need an API token with write permissions. Create one in your Sanity project's settings. Never expose this token in client-side code - instead, proxy the request through an API route or serverless function.

Document ID: You can either:

  • Generate a custom ID like drafts.my-custom-id
  • Use a UUID generator for a random ID
  • Use a timestamp or slug-based ID

Publishing: When you're ready to publish the draft, you can use the Sanity API to remove the drafts. prefix and create the published version.

Next.js Integration

If you're using Next.js (as mentioned in this community answer), create an API route to handle the form submission securely:

// pages/api/create-draft.js
import { createClient } from '@sanity/client'

const client = createClient({
  projectId: process.env.NEXT_PUBLIC_SANITY_PROJECT_ID,
  dataset: process.env.NEXT_PUBLIC_SANITY_DATASET,
  token: process.env.SANITY_WRITE_TOKEN, // Keep this secret!
  apiVersion: '2024-03-01',
  useCdn: false
})

export default async function handler(req, res) {
  if (req.method !== 'POST') {
    return res.status(405).json({ message: 'Method not allowed' })
  }

  try {
    const document = {
      _id: `drafts.${Date.now()}`,
      _type: req.body.type,
      ...req.body.fields
    }

    const result = await client.create(document)
    res.status(200).json(result)
  } catch (error) {
    res.status(500).json({ error: error.message })
  }
}

This keeps your write token secure on the server side while allowing your frontend to create drafts safely!

I was actually building out an example of this a few weeks ago and then got side tracked and couldn’t finish. There’s a good intro to forms in general in Next here . The main thing is you’d replace the database you’re sending your form to with Sanity using our JS client. In order to make it a draft, you’d need to prepend
drafts.
to the
_id
of the document.
Excellent rd! Thanks:) The good ol sidetrack 😂
I implemented something similar to what you are looking for. A blog application that had an /editor path where your could edit and create blogs outside of sanity. though if i remember correctly my sanity would automatically publish new blogs through the API.
If you are interested to see the repo just shoot me a message.
Thanks Tuomas! Actually got it working! But since we are already here, I got another question that one of you might have the answer to. Im displaying this data on a tv, and would like to update the data when I publish any changes, im doing it now with an effect, is there any way i can get the effect to fire when we update the data? The useQuery with webhook and tags perhaps? This is the current setup
  useEffect(() => {
    const fetchData = async () => {
      const data = await client.fetch(query, { weekNumber: weekNumber })
      setData(data)
      //Endre denne for å teste loading
      // setTimeout(() => {
      //   setIsLoading(false)
      // }, 10000)
    }

    fetchData()
    //Endre denne for å oppdatere på intervall
    // const refreshInterval = 30 * 1000
    // const timeoutId = setTimeout(() => {
    //   window.location.reload()
    // }, refreshInterval)

    // return () => clearTimeout(timeoutId)
  }, [weekNumber])

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?