Create custom document views with Structure Builder
In this article, we'll look at adding a custom document view to view the JSON data for our posts.
The Structure Builder API gives you control over how a document node is presented within a collapsable pane. Specifically, it allows you to set up one or more views that either return the default form or a custom React component. Each view receives a collection of props that include the document's values in different states: draft
, published
, historical
, and the currently displayed
version (for when you have selected a previous revision to a document).
This article will use the Structure Builder API to display the JSON data for a specific document. If you're unfamiliar with setting up a custom structure, read this article on setting up the basics.
Learning the Structure Builder API
This collection of articles will walk you through all the basics of using Structure Builder to create custom editing experiences.
If you've been following the earlier articles in this series, we've set our deskStructure.js
file to export a named function that contains our new structure. Alongside this, we'll now export another named function, as well.
In deskStructure.js
, add the following code:
// ./deskStructure.js
export const defaultDocumentNodeResolver = (S) =>
S.document().views([
S.view.form()
])
// ...rest of structure
Then, in sanity.config.js
, import this function and add it to the structureTool
configuration object under the key defaultDocumentNode
.
// ./sanity.config.js
import {defineConfig} from 'sanity'
import {structureTool} from 'sanity/structure'
import {deskStructure, defaultDocumentNodeResolver} from './src/structure'
import {schemaTypes} from './schemas'
export default defineConfig({
name: 'default',
projectId: '<projectId>',
dataset: 'production',
plugins: [
structureTool({
structure: deskStructure,
defaultDocumentNode: defaultDocumentNodeResolver,
}),
],
schema: {
types: schemaTypes,
},
})
In our defaultDocumentNodeResolver
function, we return an array of views for all the documents. To start us off, we're only returning the default form view. Let's look at the structure builder methods in more detail.
The .document()
method creates the way the Structure tool displays documents. In this example, it changes how all documents are rendered.
The .views()
method accepts an array of view elements which can be created using either S.view.form()
or S.view.component()
. The view elements define the items that show up in the document’s tab list.
To add a second view, we'll add a second item to the array inside the .views()
method. For this, we'll use the .view.component()
method to use a custom component.
Protip
For simplicity, we're putting our new preview component definition in the deskStructure.js
-file where we also keep all our structure builder code. In most real-world cases you probably want to separate it out into another file containing components to keep things tidy.
// ./deskStructure.js
const JsonPreview = ({document}) => (
<h1>JSON Data</h1>
)
export const defaultDocumentNodeResolver = (S) =>
S.document().views([
// Give all documents the JSON preview,
// as well as the default form view
S.view.form(),
S.view.component(JsonPreview).title('JSON')
])
// ...rest of structure
The .view.component
method takes a custom React component as an argument. The component can be chained with other methods such as .title()
to provide a title for the new view.
Our custom React component is called JsonPreview
. Custom components have the following props:
document
– an object containing the various document states and their datadocumentId
– the ID of the current documentschemaType
– the schema type of the current document
In this example, we'll only need the document
object, but to start, let's render an h1
with the string JSON Data
. We now have two tabs across the top of our documents. The tab titled "JSON" will render our h1
.
To pull data into our component, we'll need to select which version of the document we want to use. Luckily, the document
prop contains the various states of the current document. For our uses, we want to show the JSON data for the currently selected version of the document, so we'll choose the displayed
data.
// ./deskStructure.js
const JsonPreview = ({document}) => (
<> // A React fragment to have sibling elements
// Pulling the currently displayed version's title
<h1>JSON Data for "{document.displayed.title}"</h1>
// Stringifying a JSON representation of the displayed data
<pre>{JSON.stringify(document.displayed, null, 2)}</pre>
</>
)
Sometimes you only want certain tabs to display for certain document types – or even individual documents. For this, the getDefaultDocumentNode()
method comes with two options passed in: schemaType
and documentId
. We can use these with a JavaScript conditional to only build our JSON preview for certain documents.
// ./deskStructure.js
const JsonPreview = ({document}) => (
<>
<h1>JSON Data for "{document.displayed.title}"</h1>
<pre>{JSON.stringify(document.displayed, null, 2)}</pre>
</>
)
export const getDefaultDocumentNode = (S, {documentId, schemaType}) => {
// Render the JSON preview only on posts or the siteSettings document
if (schemaType === "post" || documentId === "siteSettings") {
return S.document().views([
S.view.form(),
S.view.component(JsonPreview).title('JSON')
])
}
}
//...rest of structure
With all the data available to you in each of your documents, you can put together powerful previews, contextual images, or even custom editor flows for each document or document type.
From here, take a look at the full reference documentation for everything you can do with the Structure Builder API, and build something useful to you or your editors.