Why do Articles have Editor/Preview tabs but other documents don't?

31 replies
Last updated: Jun 8, 2022
Hello, is there a simple reason why “Articles” have the Editor/Preview tabs in Studio, but ‘documents’ do not?
AI Update

There's a simple explanation for this! The Editor/Preview tabs you're seeing in some documents are not automatic - they're configured through the Structure Builder API using defaultDocumentNode.

By default, all documents in Sanity Studio only show the Editor tab. The Preview (or any additional tabs) appear when you explicitly configure them using the getDefaultDocumentNode function in your structure configuration.

Here's what's likely happening in your setup:

For "Articles" (with tabs): Your structure configuration probably has something like this:

export const getDefaultDocumentNode: DefaultDocumentNodeResolver = (S, options) => {
  if (options.schemaType === "article") {
    return S.document().views([
      S.view.form(),
      S.view.component(PreviewComponent).title('Preview')
    ])
  }
}

For other documents (without tabs): They're using the default behavior, which only shows the form editor.

How to add tabs to your documents

You can configure document views in your sanity.config.ts by:

  1. Creating a getDefaultDocumentNode function that returns different views using S.document().views()
  2. Adding it to your structureTool configuration:
import {structureTool} from 'sanity/structure'

export default defineConfig({
  plugins: [
    structureTool({
      defaultDocumentNode: getDefaultDocumentNode,
    }),
  ],
})

You can conditionally show preview tabs based on schemaType or documentId, which is why only certain document types have them.

For more details on setting this up, check out the Structure Builder documentation on creating custom document views.

Show original thread
31 replies
Are you talking about the community studio or your own or something else?
Hi
user F
we are using the Free plan studio, pushed to a sanity.studio url (or run locally with
sanity start
Articles (with Preview tab option)
Document (without)
Okay. Kind reminder that you are setting up your own schema and your own plugins. In other words, your situation is always unique because you customize the whole thing. So you can’t expect people to know what you’re talking about. 😄
So this view comes from the
iframe pane plugin. It is present provided there is a resolved URL for the preview, otherwise it’s not shown I believe.
Looking at your screenshots, it might also be because your homepage is a singleton document (judging by the absence of a second panel list). Maybe it’s handled differently then.
Ah yes, definitely that reason. The plugin is configured via the structure builder, and your structure is custom for the homepage.
Ah ok, is there a way to make this work? I couldn’t find any docs about the difference
I’m checking. 🙂
Yes, got it.
Can you show me your structure override file please?
Hmm, what might that look like? (sorry this is my first Sanity project)
Ah, is that this
deskStructure.js
import S from "@sanity/desk-tool/structure-builder";

import { ImHome, ImCog } from "react-icons/im";

import Iframe from "sanity-plugin-iframe-pane";

import resolveProductionUrl from "./resolveProductionUrl";


// Guide for structure builder: <https://www.sanity.io/docs/structure-builder-introduction>


export default () =>

S.list()

.title("Structure")

.items([

S.listItem()

.title("Homepage")

.icon(ImHome)

// Manually add in a new listItem

.child(S.document().schemaType("homepage").documentId("homepage")),

// The standard listItem - exclude some so you can't make multiples of them (e.g. singletons)

...S.documentTypeListItems().filter(

(listItem) => !["siteSettings", "homepage"].includes(listItem.getId())

),

// Add a horizontal line

S.divider(),

// Manually add in a new listItem

S.listItem()

.title("Settings")

.icon(ImCog)

.child(

S.document().schemaType("siteSettings").documentId("siteSettings")

),

]);


export const getDefaultDocumentNode = () => {

return S.document().views([

S.view.form(),

S.view

.component(Iframe)

.options({

url: (doc) => resolveProductionUrl(doc),

})

.title("Preview"),

]);

};
Right.
Replace this part:
S.document().schemaType("homepage").documentId("homepage")
With:

S.document().views([
    S.view.form(),
    S.view
      .component(Iframe)
      .options({
        url: (doc) => resolveProductionUrl(doc),
      })
      .title("Preview"),
  ]).schemaType("homepage").documentId("homepage")
Basically, wherever you see
.document()
, you need to chain the
.views(…)
that you also defined at the bottom of the file.
Do you see what I mean?
I do!
and that works!
I recommend extracting the array you pass to
.views()
in a constant and then just pass
.views(VIEWS)
everywhere you need. 😉
To avoid duplicating the views config.
Is there a docs page which explains this?
You mean that whole problem?
Maybe just the
views
bit?
And then subsequent pages or so.
Amazing. Thank you very much for your help (do you have a tipjar/paypal.me link I can send you a small thank you to?)
Aww, that’s unnecessary, thank you. 💚
Ok, thank you anyway, and have a nice day!

Sanity – Build the way you think, not the way your CMS thinks

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.

Was this answer helpful?