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

Help with nesting PageBuilder sections inside a grid

24 replies
Last updated: Jun 7, 2023
Panicing a little bit lol... for the first time in 10 years of my career. I need to deliver a project on monday, but I have a problem where I am using a PageBuilder to build all the pages based on sections. But the problem here is some pages like a Privacy & Policy have a RichtTextEditor but with a Max Width.... because this is th eonly thing on a page. All pages are dynamically created so there is no way to specify a GRID for one specific page to wrap it around the RichtTextEditor block.
Can I have a like a section something like a Grid and inside that section to add the RichTextEditor? Thanks :0
Jun 7, 2023, 8:10 PM
I’m not sure I follow. Are you talking about rendering your Portable Text on your front end?
Jun 7, 2023, 8:18 PM
Sorry Yes,I have a page builder with multiple sections which works perfect.

But I have this privacy page which should only display a Portable Text editor but this editor needs to be wrapped inside a grid/container if that makes sense?
Jun 7, 2023, 8:24 PM
Doing something like this:

import Link from "next/link"

import { PortableText } from "@portabletext/react"

import { IoIosQuote } from "react-icons/io"

import { Image } from "@/components/shared"

import { Heading } from "@/components/ui"
import { Section } from "@/components/shared"

import type { BlockContent as BlockContentType } from "@/models/sections/block-content"

import Video from "./Video"
import { cn } from "@/lib/utils"

const BlockContent = ({ data }: { data: BlockContentType }) => {
  const blocks = data.body
  const { grid } = data

  let maxWidthClass

  if (grid === "extra-large") {
    maxWidthClass = "max-w-7xl"
  }

  if (grid === "large") {
    maxWidthClass = "max-w-6xl"
  }

  if (!blocks) {
    return null
  }

  return (
    <Section>
      <div
        className={cn(
          grid ? maxWidthClass : "max-w-none",
          "py-4 prose prose-blockquote:p-3 prose-blockquote:border-accent"
        )}
      >
        <PortableText
          value={blocks}
          components={{
            types: {
              image: ({ value }) => (
                <Image src={value} width={960} height={600} alt="" />
              ),
              quote: ({ value }) => <blockquote>{value.text}</blockquote>,
              youtube: ({ value }) => (
                <Video className="!px-0 !py-0" data={value} />
              )
            },

            marks: {
              internalLink: ({ children, value }) => (
                <Link href={`${value.slug.current}`}>{children}</Link>
              ),
              externalLink: ({ children, value }) => (
                <a href={`${value.link}`} target={value.blank ? "_blank" : ""}>
                  {children}
                </a>
              ),
              italic: ({ children }) => <i>{children}</i>,
              highlight: ({ children }) => (
                <mark className="bg-transparent box-decoration-clone py-[1px] px-1 my-0 mx-[0.10rem] rounded-md bg-gradient-to-r from-sun/90 to-sun/40">
                  {children}
                </mark>
              )
            },
            block: {
              h2: ({ children }) => <Heading level="h2">{children}</Heading>,
              h3: ({ children }) => <Heading level="h3">{children}</Heading>,
              h4: ({ children }) => <Heading level="h4">{children}</Heading>,
              h5: ({ children }) => <Heading level="h5">{children}</Heading>,
              normal: ({ children }) => <p>{children}</p>,
              blockquote: ({ children }) => (
                <div className="py-1 not-prose">
                  <blockquote className="flex">
                    <IoIosQuote />
                    <p className="pl-1 text-lg font-semibold">{children}</p>
                  </blockquote>
                </div>
              )
            }
          }}
        />
      </div>
    </Section>
  )
}

export default BlockContent
Jun 7, 2023, 8:28 PM
I’m still not totally clear on the problem. At the point where you’re establishing the grid wrapper in your component, you have your data, so could you render the grid (or not) conditionally? I’m assuming you won’t change between grid and no-grid in the same page, so I don’t think this violates any React principles.
Another option could be a separate component, but again—I may not be understanding you correctly.
Jun 7, 2023, 9:16 PM
user Q
, just in case you might not be clear (in the heat of this) what
user A
means by 'conditionally', you can easily show or not any item or block of React JSX code like this:

const someFlag = true // or false, or could be a function returning a boolean

return (
  <>
    <h2>Any other preceding html or React components</h2>
    { someFlag &&
       <h3>Some html or react compoents to show if someFlag is true</h3>
         ... any lines of these ...
    }
    <h2>html, components coming after -- or more { flag && } blocks(!) </h2>
  </>
)
This is the simplest form, which should get you through by flag-enabling portions of the grid etc. code that you already have.

There are others, but let's not go there while you're getting out a delivery
🙂
Bona fortuna,
Cllive
Jun 7, 2023, 9:40 PM
user Q
Thank you for the help appreciated. My only biggest problem now I have this perfectly working pageBuilder to build all the pages I want. But the problem comes where sometimes I need to have 2 pageBuilder "section" inside a grid and columns. I tried creating an Sanity doc Grid to nest Array items inside the Pagebuilder which is also an Array of items but this won't work.
Jun 7, 2023, 9:43 PM
Do you mean you want two instances of
Page sections
in some documents?
Jun 7, 2023, 9:44 PM
Take a look at my screenshot I have 2 Page sections stacked up on each other. But in this case I need them to be inside a "flex/grid" and these 2 should be inside a column. But the PageBuilder that I am using is an array of sections. There is no way for me to add another "Grid" (section) inside this pageBuilder to be another Array of nested items.
That's my only problem I am having would love to know the best way I can solve this.
Jun 7, 2023, 9:47 PM
It should look like this: hopefully this makes a little bit sense.
Jun 7, 2023, 9:47 PM
The Page sections of this page looks like this:
Jun 7, 2023, 9:48 PM
But In my head it should be section "Grid" =&gt; with these 2 nested.
Jun 7, 2023, 9:48 PM
So that I can wrap them inside a grid on the front-end side
Jun 7, 2023, 9:48 PM
Was thinking about creating page sections like "Grid Start" and "Grid End" and in between these two.
Jun 7, 2023, 9:50 PM
based on these 2 page sections do the HTML logic
Jun 7, 2023, 9:50 PM
There is no way for me to add another “Grid” (section) inside this pageBuilder to be another Array of nested items.
Why not?
Jun 7, 2023, 9:50 PM
I have tried but I get undefined "map"
Jun 7, 2023, 9:51 PM
When I use this inside my page sections I get "map" undefined and Sanity crashes.
import {RiLayoutGridLine} from 'react-icons/ri';
import {defineField} from 'sanity';


const grid = defineField({
	name: 'grid',
	type: 'object',
	title: 'Grid',
	hidden: true,
	description: 'This is a simple grid component, all items are going to be equally wide',
	icon: RiLayoutGridLine,
	groups: [
		{
			name: 'columns',
			title: 'Columns'
		},
		{
			name: 'items',
			title: 'Items'
		}
	],
	fields: [
		{
			title: 'Title',
			name: 'title',
			type: 'string'
		},
		{
			name: 'columns',
			title: 'Columns',
			type: 'columns',
			group: 'columns'
		},
		{
			name: 'items',
			title: 'Items',
			group: 'items',
			type: 'array',
			options: {
				layout: 'grid'
			},
			of: [{type: 'blockContent'}}]
		}
	],
	preview: {
		select: {
			title: 'title'
		},
		prepare({title}: {title: string}) {
			return {
				title: `${title}`
			};
		}
	}
});

export default grid;
Jun 7, 2023, 9:52 PM
If you can show the actual error you’re getting, we can try to troubleshoot it. Is
blockContent
an array or an object?
Jun 7, 2023, 9:56 PM
Take a look! Hopefully this will do the trick!!!
Jun 7, 2023, 10:03 PM
Thanks for the help and advice Geoff I will now render it on the front-end
Jun 7, 2023, 10:04 PM
Well done all - gold stars 🙂
Jun 7, 2023, 10:12 PM
Thank you all! KINGS!!!!!! I have it Working 😄 😄 😄 😄
Jun 7, 2023, 10:22 PM
Wonderful - and you may get some sleep, then 🙂
Jun 7, 2023, 10:23 PM
haha YES very happyyyyy 🙂 Thank you sir!
Jun 7, 2023, 10:30 PM

Sanity– build remarkable experiences at scale

Sanity is a modern headless CMS that treats content as data to power your digital business. Free to get started, and pay-as-you-go on all plans.

Was this answer helpful?