Migrating v2 StructureBuilder to v3: Access document types and icons in widgets

20 replies
Last updated: Nov 30, 2025
Hey everyone, I have been having issues with migrating a v2 edit content widget, it seems that the tool was using the desk tool structureBuilder and getting the icons from a list

import StructureBuilder from '@sanity/desk-tool/structure-builder';

export function getDefaultStructure() {
  const items = StructureBuilder.documentTypeListItems();
  return StructureBuilder.list()
    .id('__root__')
    .title('Content')
    .showIcons(items.some((item) => item.getSchemaType().icon))
    .items(items);
}
which later is used as in a React component file

{getDefaultStructure().items
          .filter((item) => item.type !== 'divider')
          .map((item) => {
            const Icon = getIconComponent(item);
            return (
              <div key={item.id}>
                <Link
                  className={styles.link}
                  href={`/${getEnvironmentName()}/desk/${item.id}`}>
                  <div className={styles.iconWrapper}>
                    <Icon />
                  </div>
                  <div>{item.title}</div>
                </Link>
              </div>
            );
          })}
Okay since there seems to be no way to access the StructureBuilder, which now seems only to exist inside the deskTool plugin, is there a way to retrieve it and use it in widgets? Or is there a GROQ query to get the different available document types used in sanity desk, with their respective icons. Thanks in advance.
AI Update

I understand your struggle! In Sanity v3 (and v4), the StructureBuilder is no longer directly importable as it was in v2. However, there's a better way to access document types and their icons in your custom widgets using the useSchema hook.

Using the useSchema Hook

The useSchema hook gives you access to all schema types in your Studio, including their icons. Here's how to adapt your code:

import { useSchema } from 'sanity'

function YourWidget() {
  const schema = useSchema()
  
  // Get all document types
  const documentTypes = schema.getTypeNames()
    .map(typeName => schema.get(typeName))
    .filter(type => type?.type === 'document')
  
  return (
    <div>
      {documentTypes.map((docType) => {
        const Icon = docType.icon
        return (
          <div key={docType.name}>
            <Link
              className={styles.link}
              href={`/${getEnvironmentName()}/desk/${docType.name}`}
            >
              <div className={styles.iconWrapper}>
                {Icon && <Icon />}
              </div>
              <div>{docType.title || docType.name}</div>
            </Link>
          </div>
        )
      })}
    </div>
  )
}

How It Works

  1. useSchema() - Returns the schema object with all registered types
  2. schema.getTypeNames() - Gets all type names in your schema
  3. schema.get(typeName) - Gets the full type definition including icon, title, name, etc.
  4. Filter for documents - Only show document types (not objects, arrays, etc.)

Accessing Icons from Structure Builder

If you specifically need to replicate the Structure Builder's default list items (which includes special handling and ordering), you can use the documentTypeListItems() method within your structure configuration, but you'll need to access it differently:

import { structureTool } from 'sanity/structure'

// In your sanity.config.js
export default defineConfig({
  plugins: [
    structureTool({
      structure: (S) => {
        // S is the Structure Builder instance
        const items = S.documentTypeListItems()
        // You can export or use this data here
        return S.list()
          .title('Content')
          .items(items)
      }
    })
  ]
})

However, for custom widgets outside the structure configuration, the useSchema hook approach is the recommended pattern in v3/v4.

Important Notes

  • The icon property from schema types is already a React component, so you can render it directly
  • Document types without an icon will have icon as undefined, so check before rendering
  • The order from getTypeNames() may differ from Structure Builder's default ordering, which alphabetizes and applies special rules

This approach gives you full access to document type metadata including icons, titles, and any other schema properties you need for your custom navigation widget!

Show original thread
20 replies

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?