# Create page builder schema types https://www.sanity.io/learn/course/page-building/create-page-builder-schema-types.md Setup the initial "blocks" of content and set the foundation of your page builder schema types. 1. The schema types you'll add in this lesson follow on from those created in the [Content-driven web application foundations](https://www.sanity.io/learn/course/content-driven-web-application-foundations) course. The choices you make at this stage will determine the efficiency of content creation. Keeping your schema simple and well-structured is the key to effortless authoring. ## Learning objectives By the end of this lesson, you'll be able to: * Structure a page builder * Implement new blocks * Understand when to use references vs objects ## Setting up a page builder The page builder is typically an [array of](https://www.sanity.io/docs/array-type) [`object`](https://www.sanity.io/docs/array-type) or [`reference`](https://www.sanity.io/docs/array-type) types that can be reordered. It's the container for all your building blocks. With Sanity, there are no pre-built blocks, but it's fast and easy to create what you need. * If you use **objects**, the content is simpler to query but trapped within the document. * If you use **references**, the content can be reused between documents, and your queries must resolve them. ### Create the block schema types Let's start by creating your first `pageBuilder` block. Note that this example uses an object type to create the block. Since you are new to page builders, the following example will start with objects, and the reasons for this choice will [be explained later](https://www.sanity.io/learn/course/page-building/scaling-page-builders-and-pitfalls#s-2e72d1b5ac82). The next step is to add a `splitImage` block, a simple layout with text on one side and an image on the other, either left or right. You've definitely seen this block on many websites. [Here's a link for what this block could look like](https://v0.dev/chat/zwZtgP2aDSB?b=b_LmbyJ1dlp4v) 1. **Create** the `splitImage` block ```typescript:src/sanity/schemaTypes/blocks/splitImageType.ts import { defineField, defineType } from "sanity"; export const splitImageType = defineType({ name: "splitImage", type: "object", fields: [ defineField({ name: "orientation", type: "string", options: { list: [ { value: "imageLeft", title: "Image Left" }, { value: "imageRight", title: "Image Right" }, ], }, }), defineField({ name: "title", type: "string", }), defineField({ name: "image", type: "image", }), ], preview: { select: { title: "title", media: "image", }, prepare({ title, media }) { return { title, subtitle: "Text and Image", media }; }, }, }); ``` Now, let's add a `hero` block. This is a simple block with a title text and image. Despite the schemas looking very similar, you would usually have a hero at the top of a page, so it's a good idea to have a dedicated block for it. You may have noticed that the code snippets use a block field for the text. This is known as portable text, a powerful way to render rich text within Sanity. While it's more complex than a simple string, its flexibility makes it incredibly useful. 1. See [Presenting Portable Text](https://www.sanity.io/learn/developer-guides/presenting-block-text) in the documentation for more details [Here's a link for what this block could look like](https://v0.dev/chat/MiPurXiE59K?b=b_gUmeXji6heI) 1. **Create** the `hero` block ```typescript:src/sanity/schemaTypes/blocks/heroType.ts import { defineField, defineType } from "sanity"; export const heroType = defineType({ name: "hero", type: "object", fields: [ defineField({ name: "title", type: "string", }), defineField({ name: "text", type: "blockContent", }), defineField({ name: "image", type: "image", }), ], }); ``` 1. Getting an error with `blockContent` missing? The schema types you'll add in this lesson follow on from those created in the [Content-driven web application foundations](https://www.sanity.io/learn/course/content-driven-web-application-foundations) course. An "FAQ Block" is an ideal block for using references, allowing the same document to be reused in multiple places. If you have a list of FAQs that you want to show on multiple pages, you can create a single FAQ document and reference it from each page rather than duplicating the FAQ content. This makes it easier to maintain since you only need to update the content in one place. Let's create a FAQ document type and reference it in a block. First, let's create the FAQ document schema: In this example, the name of the block is `faqBlock` [Here's a link for what this block could look like](https://v0.dev/chat/zl4hrYbDzOg?b=b_lTKHW2wTTS4) 1. **Create** the `faq` document schema type ```typescript:src/sanity/schemaTypes/faqType.ts import { defineField, defineType } from "sanity"; export const faqType = defineType({ name: "faq", title: "FAQ", type: "document", fields: [ defineField({ name: "title", type: "string", }), defineField({ name: "body", type: "blockContent", }), ], }); ``` 1. **Create** the `faqAccordion` block, which will reference the FAQ document. ```typescript:src/sanity/schemaTypes/blocks/faqsType.ts import { defineField, defineType } from "sanity"; export const faqsType = defineType({ name: "faqs", title: "FAQs", type: "object", fields: [ defineField({ name: "title", type: "string", }), defineField({ name: "faqs", title: "FAQs", type: "array", of: [{ type: "reference", to: [{ type: "faq" }] }], }), ], }); ``` Finally, one more block. This one is a features block, and this is going to get a little more complex with an array of features (as a block) inside a block. [Here's a link for what this block could look like](https://v0.dev/chat/z0zxFeAPm1z?b=b_ZpymafJ4kCT) 1. **Create** the `features` block ```typescript:src/sanity/schemaTypes/blocks/featuresType.ts import { defineField, defineType } from "sanity"; export const featuresType = defineType({ name: "features", type: "object", fields: [ defineField({ name: "title", type: "string", }), defineField({ name: "features", type: "array", of: [ defineField({ name: "feature", type: "object", fields: [ defineField({ name: "title", type: "string", }), defineField({ name: "text", type: "string", }), ], }), ], }), ], }); ``` ### Create the page builder schema type Okay great, you have got your blocks. Now let's put them together in your page builder component. The order of the blocks is how it will appear when a user adds a new block to the array. 1. **Create** the `pageBuilder` schema type ```typescript:src/sanity/schemaTypes/pageBuilderType.ts import { defineType, defineArrayMember } from "sanity"; export const pageBuilderType = defineType({ name: "pageBuilder", type: "array", of: [ defineArrayMember({ type: "hero" }), defineArrayMember({ type: "splitImage" }), defineArrayMember({ type: "features" }), defineArrayMember({ type: "faqs" }), ], }); ``` ### Create the page document type The schema types in your Sanity Studio for now are only useful for writing blog posts. The pages being built with this schema have a different intention to those, and so should be stored in a distinct schema type. 1. **Create** a `page` document schema type ```typescript:src/sanity/schemaTypes/pageType.ts import { DocumentIcon } from "@sanity/icons"; import { defineField, defineType } from "sanity"; export const pageType = defineType({ name: "page", title: "Page", type: "document", icon: DocumentIcon, fields: [ defineField({ name: "title", type: "string", }), defineField({ name: "slug", type: "slug", options: { source: "title", }, }), defineField({ name: "content", type: "pageBuilder", }), defineField({ name: "mainImage", type: "image", options: { hotspot: true, }, }), ], preview: { select: { title: "title", subtitle: "slug.current", }, }, }); ``` ### Add your new types to the Studio schema Finally, update the schema types index file to import all of these newly created schema types. 1. **Update** your registered schema types ```typescript:src/sanity/schemaTypes/index.ts // ...all your existing imports import { pageType } from "./pageType"; import { pageBuilderType } from "./pageBuilderType"; import { faqType } from "./faqType"; import { faqsType } from "./blocks/faqsType"; import { featuresType } from "./blocks/featuresType"; import { heroType } from "./blocks/heroType"; import { splitImageType } from "./blocks/splitImageType"; export const schema: { types: SchemaTypeDefinition[] } = { types: [ // ...all your existing schema types pageType, pageBuilderType, faqType, faqsType, featuresType, heroType, splitImageType, ], }; ``` ### Update Studio Structure The desk structure will now include `page` and `faq` type documents, but won't display them nicely with plurals. 1. **Update** the Studio's structure configuration ```typescript:src/sanity/structure.ts import type { StructureResolver } from "sanity/structure"; // https://www.sanity.io/docs/structure-builder-cheat-sheet export const structure: StructureResolver = (S) => S.list() .title("Blog") .items([ S.documentTypeListItem("post").title("Posts"), S.documentTypeListItem("category").title("Categories"), S.documentTypeListItem("author").title("Authors"), S.divider(), S.documentTypeListItem("page").title("Pages"), S.documentTypeListItem("faq").title("FAQs"), S.divider(), ...S.documentTypeListItems().filter( (item) => item.getId() && !["post", "category", "author", "page", "faq"].includes(item.getId()!) ), ]); ``` ## Check it's working With all of these new schema types registered you should now be able to create Page type documents with the Page Builder field allowing you to add any one of four blocks. ![Sanity Studio showing a page being edited with a block selector menu open](https://cdn.sanity.io/images/3do82whm/next/325dc7ddd53dfa0c57f833c81537e49e9497a4b9-2240x1480.png) Now that your page builder schema is set up, all the fundamental building blocks are in place. Next, you can add new blocks, reorder them, and update the array as needed.