# Render page builder blocks https://www.sanity.io/learn/course/page-building/rendering-page-builder-blocks.md Setup the unique components for each individual "block" to render on the page. The example components in this lesson have been given deliberately simple designs. Feel free to redesign them with much more _flair_. You'll notice also the props for each component has been typed from the `PAGE_QUERYResult` generated from Sanity TypeGen. The type itself looks _quite_ gnarly, but it will be constantly updated as you make future changes to your schema types and queries. ## Create block components 1. **Create** a component to render the Hero block ```tsx:src/components/blocks/hero.tsx import { PortableText } from "next-sanity"; import Image from "next/image"; import { Title } from "@/components/title"; import { urlFor } from "@/sanity/lib/image"; import { PAGE_QUERYResult } from "@/sanity/types"; type HeroProps = Extract< NonNullable["content"]>[number], { _type: "hero" } >; export function Hero({ title, text, image }: HeroProps) { return (
{title ? (

{title}

) : null}
{text ? : null}
{image ? ( ) : null}
); } ``` 1. **Create** a component to render the FAQs block ```tsx:src/components/blocks/faqs.tsx import { PAGE_QUERYResult } from "@/sanity/types"; import { PortableText } from "next-sanity"; type FAQsProps = Extract< NonNullable["content"]>[number], { _type: "faqs" } >; export function FAQs({ _key, title, faqs }: FAQsProps) { return (
{title ? (

{title}

) : null} {Array.isArray(faqs) ? (
{faqs.map((faq) => (
{faq.title}
{faq.body ? : null}
))}
) : null}
); } ``` 1. **Create** a component to render the Features block ```tsx:src/components/blocks/features.tsx import { PAGE_QUERYResult } from "@/sanity/types"; type FeaturesProps = Extract< NonNullable["content"]>[number], { _type: "features" } >; export function Features({ features, title }: FeaturesProps) { return (
{title ? (

{title}

) : null} {Array.isArray(features) ? (
{features.map((feature) => (

{feature.title}

{feature.text}

))}
) : null}
); } ``` 1. **Create** a component to render the Split Image block ```tsx:src/components/blocks/split-image.tsx import Image from "next/image"; import { urlFor } from "@/sanity/lib/image"; import { PAGE_QUERYResult } from "@/sanity/types"; import { stegaClean } from "next-sanity"; type SplitImageProps = Extract< NonNullable["content"]>[number], { _type: "splitImage" } >; export function SplitImage({ title, image, orientation }: SplitImageProps) { return (
{image ? ( ) : null}
{title ? (

{title}

) : null}
); } ``` ## Render the page builder content Now we have components for each block, we need to render them in order. Each array item has a distinct `_type` attribute, which you can switch over to render the correct component. Each item also contains a unique (to the array) `_key` value, which can be passed to React as a `key` prop—required by React for performant and consistent rendering of an array. We have also passed the remaining props to the block component using the spread operator. 1. **Create** the `PageBuilder` component to render all the content of the page ```tsx:src/components/page-builder.tsx import { Hero } from "@/components/blocks/hero"; import { Features } from "@/components/blocks/features"; import { SplitImage } from "@/components/blocks/split-image"; import { FAQs } from "@/components/blocks/faqs"; import { PAGE_QUERYResult } from "@/sanity/types"; type PageBuilderProps = { content: NonNullable["content"]; }; export function PageBuilder({ content }: PageBuilderProps) { if (!Array.isArray(content)) { return null; } return (
{content.map((block) => { switch (block._type) { case "hero": return ; case "features": return ; case "splitImage": return ; case "faqs": return ; default: // This is a fallback for when we don't have a block type return
Block not found: {block._type}
; } })}
); } ``` 1. **Update** the dynamic page route to use the `PageBuilder` component ```tsx:src/app/(frontend)/[slug]/page.tsx import { PageBuilder } from "@/components/page-builder"; import { sanityFetch } from "@/sanity/lib/live"; import { PAGE_QUERY } from "@/sanity/lib/queries"; export default async function Page({ params, }: { params: Promise<{ slug: string }>; }) { const { data: page } = await sanityFetch({ query: PAGE_QUERY, params: await params, }); return page?.content ? : null; } ``` You should now be able to create page documents, use all of the blocks from the Page Builder array we have created, and preview changes as you author them. ![Sanity Studio Presentation tool showing a website layout](https://cdn.sanity.io/images/3do82whm/next/24b3f7de0a18f9708281c266ec86366427261ebf-2240x1480.png) For now you have click-to-edit functionality in Presentation. Before going any further, let's use everything we've built so far to create the application's home page.