👋 Next.js Conf 2024: Come build, party, run, and connect with us! See all events

Migrating New Document Templates

The newDocumentOptions lets you configure templates for new documents that can be reactive to contextual info such as the currently logged-in user.

Templates for “New Document”-items should be declared on the document.newDocumentOptions property. It accepts either a static array of template objects or a callback function that returns the same. The callback function is invoked with the current value as its first argument and a configuration context object as its second.

Minimal example

In v2, you would set it up like this:

// sanity.json
{
  "root": true,
  "project": {
    "name": "My Project"
  },
  // ...
  "parts": [
    {
      "name": "part:@sanity/base/initial-value-templates",
      "path": "./initialValueTemplates.js"
    },
    {
      "name": "part:@sanity/base/new-document-structure",
      "path": "./newDocumentStructure.js"
    }
  ]
}

// ./newDocumentStructure.js
import S from '@sanity/base/structure-builder'

const personTemplateId = 'personWithRole'
const roles = [
  {name: 'developer', title: 'Developer'},
  {name: 'designer', title: 'Designer'},
  {name: 'admin', title: 'Administrator'},
  {name: 'manager', title: 'Manager'}
]

export default [
  ...roles.map(role =>
    S.initialValueTemplateItem(personTemplateId, {role: role.name})
      .id(`personRole-${role.name}`)
      .title(role.title)
  ),
  ...S.defaultInitialValueTemplateItems()
]

In v3, you would do something like this:

v3

// sanity.config.ts
import {defineConfig} from 'sanity'
import {templates} from './schema/templates'

export default defineConfig({
  name: 'default',
  title: 'My Cool Project',
  projectId: 'my-project-id',
  dataset: 'production',
  schema: {
    templates: [
      {
        id: 'personWithRole',
        schemaType: 'person',
        title: 'Person with Role',
        // See `document.newDocumentOptions[].parameters.name`
        parameters: [{name: 'role', type: 'string'}],
        value: ({role}) => ({role}),
      },
    ],
  },
  document: {
    newDocumentOptions: [
      {name: 'developer', title: 'Developer'},
      {name: 'designer', title: 'Designer'},
      {name: 'admin', title: 'Administrator'},
      {name: 'manager', title: 'Manager'},
    ].map((roleExample) => ({
      id: 'personWithRole',
      templateId: 'personWithRole',
      type: 'initialValueTemplateItem',
      title: roleExample.title,
      parameters: {name: roleExample.name},
    })),
  },
})

The example above shows you a combination of using Initial Value Templates to automatically generate a new person document that takes a parameter called role and uses its value for the role field type on the person document type.

In the document property for the Workspace configuration, we find newDocumentOptions that takes an array of objects that define how the New document options should behave and what Initial Value Template they should invoke. In the example, we're keeping the code dry by looping over an array with the different options. Notice that we pass name into the parameters.name property. This is the value that's used by the schema.templates.value function.

New features

Returning templates based on user role

We can also return initial value templates based on the current user or other contextual variables. Building on the minimal example above is how to return only the new document templates mapping the predefined initial values with the role value of the current user.

// sanity.config.ts
import {defineConfig} from 'sanity'
import {templates} from './schema/templates'

export default defineConfig({
  // ...
  document: {
    // NOTE: the function variant of this API is useful for conditionals
    newDocumentOptions: (prev, {currentUser, creationContext}) => {
      // the `currentUser` and `creationContext` can be used to conditionally add templates
      if (currentUser.roles.find((role) => role.name === 'admin')) {
        return [
          // `prev` is equivalent to `S.defaultInitialValueTemplateItems()`
          ...prev,
          {
            id: 'adminRole',
            templateId: 'personWithRole',
            type: 'initialValueTemplateItem',
            parameters: {role: 'admin'},
          },
        ]
      }
      if (creationContext.type === 'document' && creationContext.schemaType === 'book') {
				// this could be used to change the options in the create-new menu for refs in place
			}

      return prev
    },
  },
})

Feedback or questions?

These guides are under development. If you have questions or suggestions for improvement, then we want to hear from you. Get in touch via our GitHub discussions page.

Was this article helpful?