👀 Our most exciting product launch yet 🚀 Join us May 8th for Sanity Connect

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.

Setting up deskStructure.js to create a new default document node structure

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.

S.document()

The .document() method creates the way the Structure tool displays documents. In this example, it changes how all documents are rendered.

.views()

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.

Adding a second view to all documents

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

.view.component()

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.

Custom component: JsonPreview()

Our custom React component is called JsonPreview. Custom components have the following props:

  • document – an object containing the various document states and their data
  • documentId – the ID of the current document
  • schemaType – 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.

A blog post showing the H1 "JSON Data"

Displaying dynamic data from the document

JSON displaying for the current document.

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>
 
  </>
)

Define views for specific schemas or documents

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

Next steps

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.

Was this article helpful?