3.4 KiB
3.4 KiB
title, description
| title | description |
|---|---|
| Sanity Studio Structure Rules | Rules for customizing the Sanity Studio Structure (S.structure). |
Sanity Studio Structure Rules
1. Setup
Custom structure is defined in sanity.config.ts using the structureTool.
import { structureTool } from 'sanity/structure'
import { structure } from './src/structure'
export default defineConfig({
// ...
plugins: [
structureTool({ structure })
]
})
2. Structure Definition
Location: src/structure/index.ts
Use a function that receives S (StructureBuilder).
import type { StructureResolver } from 'sanity/structure'
export const structure: StructureResolver = (S) =>
S.list()
.title('Content')
.items([
// ... items
])
3. Organization Principles
- Singletons First: Place critical site-wide settings (Global Settings, Homepage) at the top.
- Dividers: Use
S.divider()to visually separate logical groups. - Filtered Lists: Always exclude Singleton documents from generic
documentTypeListitems to avoid duplication.
4. Singleton Pattern (Critical)
Singletons are enforced via Structure, NOT schema options. There is no singleton: true schema option.
How Singletons Work
- Use
S.document().documentId('fixed-id')to lock the document to a specific ID. - Filter the type from generic lists to prevent duplicate entries.
Singleton Helper Function
// Helper to create singleton list items
function createSingleton(S: StructureBuilder, typeName: string, title: string, icon?: ComponentType) {
return S.listItem()
.title(title)
.icon(icon)
.child(
S.document()
.schemaType(typeName)
.documentId(typeName) // Fixed ID = singleton
.title(title)
)
}
// Usage
createSingleton(S, 'settings', 'Site Settings', CogIcon)
Querying Singletons
// By fixed ID (most efficient)
*[_id == "settings"][0]
// By type (works but slower)
*[_type == "settings"][0]
For localized singletons (e.g., homepage per language), see localization.md Section 6.
5. Implementation Pattern
// Define singleton types to exclude from generic lists
const SINGLETONS = ['settings', 'homePage']
export const structure: StructureResolver = (S) =>
S.list()
.title('Website Content')
.items([
// 1. Singletons
S.listItem()
.title('Site Settings')
.icon(CogIcon)
.child(S.document().schemaType('settings').documentId('settings')),
S.divider(),
// 2. Content Verticals
S.listItem()
.title('Blog')
.child(
S.list()
.title('Blog Content')
.items([
S.documentTypeListItem('post').title('Posts'),
S.documentTypeListItem('author').title('Authors'),
])
),
S.divider(),
// 3. Remaining Documents (Filtered)
...S.documentTypeListItems().filter(
(listItem) => !SINGLETONS.includes(listItem.getId() as string)
)
])
6. Views (Split Pane)
Add "Web Preview" or other views to documents.
export const defaultDocumentNode: DefaultDocumentNodeResolver = (S, { schemaType }) => {
switch (schemaType) {
case `post`:
return S.document().views([
S.view.form(), // Default form
S.view.component(PreviewComponent).title('Preview') // Custom view
])
default:
return S.document().views([S.view.form()])
}
}