Structuring Nested Categories and Tags in Sanity Desk

5 replies
Last updated: Sep 11, 2022
So I struggle with structuring my documents. I have tags that are categorised. I want to be able to create a category and within that category I want to create tags in sanity.
this is how far I got. I tried to use filter in deskStructure. But then I wasn't able to create more categories.

I am not sure what should be my approach here. Any ideas or tips?
😅
AI Update

I totally get the frustration - this is a really common pattern people need! The key issue you're running into is that filtered lists in Structure Builder are read-only views. You can't create new documents directly in them because Sanity doesn't know what filter values to pre-populate.

Here's the best approach that gives you both organized browsing AND the ability to create documents:

The Solution: Separate Document Types with References

Create two document types where tags reference their parent category:

// schemas/category.ts
export default {
  name: 'category',
  type: 'document',
  title: 'Category',
  fields: [
    {
      name: 'title',
      type: 'string',
      title: 'Title',
      validation: (Rule) => Rule.required()
    },
    {
      name: 'slug',
      type: 'slug',
      title: 'Slug',
      options: { source: 'title' }
    }
  ]
}

// schemas/tag.ts
export default {
  name: 'tag',
  type: 'document',
  title: 'Tag',
  fields: [
    {
      name: 'title',
      type: 'string',
      title: 'Title',
      validation: (Rule) => Rule.required()
    },
    {
      name: 'category',
      type: 'reference',
      title: 'Category',
      to: [{type: 'category'}],
      validation: (Rule) => Rule.required()
    }
  ]
}

Structure Builder Setup

Now create a Structure Builder configuration that gives you both the hierarchical view and flat creation lists:

// structure/index.ts
import type {StructureResolver} from 'sanity/structure'

export const structure: StructureResolver = (S) =>
  S.list()
    .title('Content')
    .items([
      // Hierarchical browsing view
      S.listItem()
        .title('Tags by Category')
        .child(
          S.documentTypeList('category')
            .title('Categories')
            .child((categoryId) =>
              S.documentList()
                .title('Tags')
                .filter('_type == "tag" && category._ref == $categoryId')
                .params({ categoryId })
            )
        ),
      
      S.divider(),
      
      // Flat lists for creating new documents
      S.documentTypeListItem('category').title('All Categories'),
      S.documentTypeListItem('tag').title('All Tags'),
    ])

Wire it up in your config:

// sanity.config.ts
import {defineConfig} from 'sanity'
import {structureTool} from 'sanity/structure'
import {structure} from './structure'

export default defineConfig({
  // ...other config
  plugins: [
    structureTool({structure}),
    // ...other plugins
  ],
  // ...schemas
})

How to Use This Setup

To create a new category:

  1. Go to "All Categories" in the sidebar
  2. Click the "+" button
  3. Fill in the category details

To create a new tag:

  1. Go to "All Tags" in the sidebar
  2. Click the "+" button
  3. Fill in the tag title and select its category from the reference field

To browse tags by category:

  1. Go to "Tags by Category"
  2. Click on a category
  3. See all tags filtered to that category

Why This Works

The "Tags by Category" view uses child resolvers to create a hierarchical browsing experience - perfect for viewing and editing existing content in an organized way. The "All Categories" and "All Tags" lists give you unfiltered access where Sanity can properly handle document creation without needing to guess filter values.

This pattern is exactly how parent-child taxonomies are meant to work in Sanity. You get the best of both worlds: intuitive organization for browsing/editing and straightforward workflows for creating new content! 😊

Show original thread
5 replies
Hello
user E
The problem you’re seeing, is because you try to define the structure within a document.
*These are separate in Sanity*: one is the
schemas
, where you define your
documents
and
objects
, one is your structure in the
desk
, which is done with the Structure-Builder API
These 2 guides could help you setup a
desk structure
you want to get working:
https://www.sanity.io/docs/structure-builder-introduction
https://www.sanity.io/guides/getting-started-with-structure-builder In addition: *think of nesting documents as referencing each other*: so setting up
references should be your way to go in your schemas!
I am unsure, which relations your categories, tags and other docs will have, but maybe set those up first with the help of the explanations from above.
After setting up your custom desk structure, you can then use
initialValueTemplates in the desk structure to pre-define, which references the newly created tags/categories will have.
But first: get accustomed to
references
(and
arrays
of references) and decide which logic they will follow and then take the next step of setting up a custom
desk structure
. Then adding
initalValueTemplates
and voila 😉
Thanks! We actually dropped that structure that I showed here and went for references. This is very helpful. I will look it this further :smiling-sun:
If you drop stuff, can you please mark your questions as resolved by adding to the message, I am alone atm and have spent quite a lot of time with your stuff which you no longer need.
Sorry I will do that next time. 🙏
Don't worry we all forget things especially when we are stressed because things don't work. 😊 So we remind people.

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?