
Grab your gear: The official Sanity swag store
Read Grab your gear: The official Sanity swag storeBased on the Structure Builder API documentation, you can add custom menu items to the document list pane using the menuItems() method, but there's an important limitation to be aware of.
You can add custom menu items to a document list pane like this:
// structure.ts
export const structure = (S) =>
S.list()
.title('Content')
.items([
S.documentTypeListItem('post')
.child(
S.documentList()
.title('Posts')
.schemaType('post')
.filter('_type == "post"')
.menuItems([
S.menuItem()
.title('My Custom Action')
.icon(() => 'âś“')
.action(() => {
// Your action handler here
}),
// Add ordering menu items
S.orderingMenuItem({by: [{field: 'publishedAt', direction: 'desc'}]}),
S.orderingMenuItem({by: [{field: 'title', direction: 'asc'}]}),
])
)
])However, the key limitation is that menuItem() actions don't have a built-in way to dynamically update the parent document list's filter. The menu items can trigger custom actions, but they can't directly modify the list's filter state like you might expect.
Since direct filter menu actions aren't fully supported, here's a more practical approach that significantly improves UX over basic "folder" grouping:
export const structure = (S) =>
S.list()
.title('Content')
.items([
// Create a dedicated Posts section
S.listItem()
.title('Posts')
.icon(() => 'đź“„')
.child(
S.list()
.title('Posts')
.items([
// All posts
S.listItem()
.title('All Posts')
.icon(() => 'đź“‹')
.child(
S.documentList()
.title('All Posts')
.schemaType('post')
.filter('_type == "post"')
.defaultOrdering([{field: 'publishedAt', direction: 'desc'}])
),
// Published only
S.listItem()
.title('Published')
.icon(() => 'âś“')
.child(
S.documentList()
.title('Published Posts')
.schemaType('post')
.filter('_type == "post" && !(_id in path("drafts.**"))')
),
// Drafts only
S.listItem()
.title('Drafts')
.icon(() => '📝')
.child(
S.documentList()
.title('Draft Posts')
.schemaType('post')
.filter('_type == "post" && _id in path("drafts.**")')
),
S.divider(),
// Dynamic category filtering
S.listItem()
.title('By Category')
.child(
S.documentTypeList('category')
.title('Select Category')
.child(categoryId =>
S.documentList()
.title('Posts')
.schemaType('post')
.filter('_type == "post" && $categoryId in categories[]._ref')
.params({categoryId})
)
),
])
),
])This approach gives you:
For sort actions, use the defaultOrdering() method, and Sanity will automatically add sort options to the pane menu:
S.documentList()
.title('Posts')
.filter('_type == "post"')
.defaultOrdering([{field: 'publishedAt', direction: 'desc'}])While this isn't exactly a dropdown filter in the menu bar, this nested list structure provides much better UX than basic GROQ filter folders, and it's the recommended pattern for organizing filtered views in Sanity Studio v3.
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.
Content operations
Content backend


The only platform powering content operations
By Industry


Tecovas strengthens their customer connections
Build and Share

Grab your gear: The official Sanity swag store
Read Grab your gear: The official Sanity swag store