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 function that contains our new structure. Alongside this, we'll now export a named function, as well.

To prepare to change the document structure, we need to export a function named getDefaultDocumentNode.

// /deskStructure.js
import S from '@sanity/desk-tool/structure-builder'

export const getDefaultDocumentNode = () => {
  // Return all documents with just 1 view: the form
  return S.document().views([
    S.view.form()
  ])
}

export default () => {
  // Where we have our custom list structure
}

In the function, we return an array of views for all the documents. To start, let's make sure that the default form view is there.

S.document()

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

.views()

The .views() method accepts an array of view type methods: S.form or S.component. These methods will define what items show up in a tabbed view for the document.

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.

// /deskStructure.js
import S from '@sanity/desk-tool/structure-builder'
import React from 'react'

const JsonPreview = ({document}) => (
// The JSON preview
<h1>JSON Data</h1>
)
export const getDefaultDocumentNode = () => { // Give all documents the JSON preview, // as well as the default form view return S.document().views([ S.view.form(),
S.view.component(JsonPreview).title('JSON')
]) }

.component()

The .component method takes a custom React component as an argument. Since this will be a React component, we need to make sure to import React at the start of our file. 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
import S from '@sanity/desk-tool/structure-builder'
import React from 'react'

const JsonPreview = ({document}) => (
  <>
    <h1>JSON Data for "{document.displayed.title}"</h1>
    <pre>{JSON.stringify(document.displayed, null, 2)}</pre>
  </>
)

export const getDefaultDocumentNode = ({documentId, schemaType}) => {
// Render the JSON preview only on posts or the siteSettings document
if (schemaType === "post" || documentId === "siteSettings") {
console.log({documentId}) return S.document().views([ S.view.form(), S.view.component(JsonPreview).title('JSON') ]) } }

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?