How to add "New document" button in mixed folder/document hierarchy and set parent field automatically?

4 replies
Last updated: Mar 20, 2023
I’m setting up a user-configurable hierarchy, and starting to get happy with how it looks now.When I know I’m on the last level I can use
documentTypeList
to get a document list with a “New document” button. But for those cases where there is a mix of folders and documents, how can I get the “New document”-button to appear?
Also, for the newly created document I would like the field for it’s parent to be automatically filled. What is the best way to do this? Can I access the id of the parent folder from the
initialValue
block somehow?
AI Update

When building a user-configurable hierarchy in Sanity's Structure Builder, getting the "New document" button to appear in a mixed list of folders and documents requires using initialValueTemplates(). Here's how to solve both parts of your question:

Adding the "New Document" button

For document lists that mix folders and documents, you need to configure the list with initialValueTemplates() and canHandleIntent(). Here's the pattern from the parent-child taxonomy guide:

S.documentTypeList(schemaType)
  .title('Children')
  .filter(`_type == $schemaType && parent._ref == $parentId`)
  .params({schemaType, parentId: parent._id})
  .canHandleIntent(
    (intentName, params) =>
      intentName === 'create' && params.template === 'category-child'
  )
  .initialValueTemplates([
    S.initialValueTemplateItem('category-child', {
      parentId: parent._id,
    }),
  ])

The key methods are:

  • initialValueTemplates() - tells the list which template to use for creating new documents, which shows the "New document" button
  • canHandleIntent() - ensures the creation intent is handled by this specific list

Pre-filling the parent field

Yes, you can absolutely access the parent folder's ID in your initial value template! Configure this in your sanity.config.ts:

export default defineConfig({
  // ...other config
  schema: {
    types: schemaTypes,
    templates: (prev) => {
      const childTemplate = {
        id: 'category-child',
        title: 'Category: Child',
        schemaType: 'category',
        parameters: [{name: 'parentId', title: 'Parent ID', type: 'string'}],
        // The parentId value gets passed from the Structure Builder
        value: ({parentId}: {parentId: string}) => ({
          parent: {_type: 'reference', _ref: parentId},
        }),
      }
  
      return [...prev, childTemplate]
    },
  },
})

The parameters array defines what can be passed to the template, and the value function receives those parameters and returns the initial values for your document. When you pass parentId through initialValueTemplates() in your Structure Builder (as shown above), it automatically pre-fills the parent reference field.

This approach gives you a clean workflow where authors can create child documents from within a parent's context, and the relationship is automatically established. The complete working example is available in the Creating a Parent/Child Taxonomy guide.

Show original thread
4 replies
Hmm, this may not be possible, but you can try a few things.First, add an
intent handler method . That may force a create new button to show up but I recall someone mentioning. having issues with it in the past.
You could also try adding a
menu item with a creation action if that doesn’t work.
Thanks,
intent
did the trick!
I could wish for some more examples in the documentation at this point, but I found something in the Community Studio code that I made into this:


S.list()
.title(category.title)
.menuItems(
  [
    {
      title: 'Create new',
      icon: ComposeIcon,
      intent: {
        type: 'create',
        params: {
          type: 'article'
        },
      },
      showAsAction: true
    } 
])
This shows a nice compose icon, and it will create a new article document. It is slightly different behaviour from the default compose button you get from a
documentTypeList
, it doesn’t open the new document in the pane to the right, but on the root level. Any way to force it to open in the next pane?
It might be related the second part of my question, how to open the new document with parent already populated. Is the studio context available in the schema definition, so I can point to the id of the previous pane?
The id is available in the URL, but that feels a bit dirty.
Aha, I found out how to create a new document with parent pre-filled with the category-child template example in the Migrating Initial Value Templates tutorial.
Now I only need to find out how to open the new document in the right pane…
That would be another intent handler! For example:
S.documentList('tag')
                .title('Tags')
                .defaultOrdering([{field: 'title', direction: 'asc'}])
                .menuItems(S.documentTypeList('tag').getMenuItems())
                .filter('_type == $type')
                .params({type: 'tag'})
                .canHandleIntent(S.documentTypeList('tag').getCanHandleIntent())

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?