Components

Block Matcher

Our BlockMatcher component is a useful tool to help you create page builder functionality for your editors. It gives them the flexibility to add blocks of their choice from a pre-defined list and order and re-order them in their preferred layout.

This guide will take you through how to set up a block for this type of functionality and how to implement the component in your Next.js codebase.

1 - Create the page content type

Within your site in Contento, go to the Manage Content Types tab, click “Add new content type” and select Page. Complete the name field, which will auto generate the handle (we’ve used general_page for this guide). We will also use the dynamic {slug} token for the URI setting so that all top-level pages will use this content type.

A title field will be automatically generated. Click the + button in the black circle to add a new field.

Give the field a name, we recommend something that describes the group of possible blocks. So in this case we’re going to use “Content” as this is the primary content of the page. We recommend making it a required field as you probably always want there to be some kind of content on the page.

Choose the Blocks field type. If you have already created other blocks on your site they will appear in the list on the left. You can choose which blocks you wish to be available for the editor to choose from, as you select them they will appear in the list on the right hand side. If you haven’t created any yet the list will be blank. That is fine for now, we will create a few example blocks in Step 2 and update this field later. Click Create.

2 - Create the blocks

Go back to the Manage Content Types tab and add another, this time selecting Block. We will name this Example Block One. Click Create then go back and do the same for Example Block Two and Example Block Three.

Now we can go back to the Manage Content Types tab again and edit the general_page content type. Click on the cog icon on the Content field to access the field settings.

Select the three example blocks we created, and they will move to the list on the right hand side. Click save.

3 - Create an example page

Next, go to the Content and click the “Add new” button. Select the General Page content type we first created and a new draft page will be created.

Give the page a name such as Example Page Builder and then click “Add New Block” in the Content field. Add the blocks we just created and give them each a title. Now Save and then Publish the page.

4 - Create the block components

Create a component file for each of block content type within the folder app > components > blocks. We use the convention of having the filename match the name of the block e.g. ExampleBlockOne.tsx or ExampleBlockTwo.tsx. Copy and paste in the code below for each block and rename the function accordingly.

import { BlockData } from '@gocontento/client/lib/types'

export default function ExampleBlockOne({ block }: { block: BlockData }) {
  return (
   <div className="bg-zinc-100 px-16 py-6 text-center mb-5">{block.fields.title.text}</div>
  )
}

Next create a BlockMatcher.tsx file in app > components and paste in the following code. It uses a switch statement within the function to check the content_type of the block and then outputs the associated component for that block type. Ensure your components are imported correctly at the top of the file, and that each case is returning the correct component.

'use client'

import { useId } from 'react'
import { BlockData } from '@gocontento/client'
import ExampleBlockOne from './blocks/ExampleBlockOne'
import ExampleBlockTwo from './blocks/ExampleBlockTwo'
import ExampleBlockThree from './blocks/ExampleBlockThree'


export default function BlockMatcher({ blocks }: { blocks: BlockData[] }) {
  
  const id = useId()

  return blocks.map((block: BlockData, index) => {
    switch (block.content_type.handle) {
      case 'example_block_one':
        return <ExampleBlockOne key={id + '-' + index} block={block} />
        
      case 'example_block_two':
        return <ExampleBlockTwo key={id + '-' + index} block={block} />
        
      case 'example_block_three':
        return <ExampleBlockThree key={id + '-' + index} block={block} />

      default:
        return (
          <div className="py-16">
            <div
              key={id + '-' + index}
              className="prose max-w-none border-t-8 border-red-400 bg-zinc-100 p-4"
            >
              <h2 className="mb-0 text-red-400">
                Invalid block - {block.content_type.name}
              </h2>
              <p>
                Please check you have added the block to the block matcher and
                the case matches the{' '}
                <span className="font-semibold">content_type.handle</span>
              </p>

              <pre className="max-h-[40vh]">
                {JSON.stringify(block, null, '  ')}
              </pre>
            </div>
          </div>
        )
    }
  })
}

If there is an error because the block is being used in the CMS but has not been added to the switch statement, or maybe the content type handle does not match what is being received from the CMS, then an error box will be outputted with the name and handle of the content type that needs fixing.

For example, oops I spelt the content type handle wrong:

Example spelling error: 'tow' instead of 'two'

5 - Run the dev server

Start your development server and check the slug of the example page you created, in this case localhost:3000/example-page-builder.

Now you should see the three example blocks we created and their title text being rendered in a list:

You can use this method to make very flexible layouts for your editors to use. Go ahead and add your own blocks to your site, create a component for each block for the front end layout and then add them to the BlockMatcher component for rendering.

Happy building!

Hollie Duncan

Written by Hollie Duncan

Updated

Previous
Content Modelling