DEV Community

Cover image for How to create custom content bricks in React Bricks
Dsalinasgardon
Dsalinasgardon

Posted on • Originally published at reactbricks.com

How to create custom content bricks in React Bricks

If you have been following along, you may have read the tutorial on how to create a blog with React Bricks and Next.js. This guide builds upon that tutorial, so you will need a working React Bricks app before you can proceed and create your own content blocks.

In this tutorial, we will explore the structure of a React Bricks project, focusing on the /bricks folder. We'll look at how bricks are organized and learn how to create new custom bricks to implement your own corporate image.

Prerequisites

  • A code editor, like VSCode
  • Basic knowledge of React
  • A working React Bricks app, created following the previous tutorial

What is a brick?

In simple terms, bricks are special React components that are visually editable and which props can be customized by content creators using a set of sidebar controls.

Creating our first brick

Exploring the /bricks folder

First, let’s open our code editor. Ready? Cool.

The /bricks folder is a crucial part of your React Bricks project. It contains the bricks, which are the building blocks for your website's pages.

If you go to your code editor, you can find the react-bricks/bricks directory in your project structure. The bricks folder in the starter projects with Tailwind is divided into two subfolders:

  • react-bricks-ui: This is where the pre-made bricks are located. You can use them to experiment with React Bricks, but they are typically deleted for a real corporate website, where a custom design system is needed.
  • custom: here you can find two example custom bricks. This is the starting point where you will create all of your custom bricks to implement the corporate image of you company or that of your customers, if you are a digital agency.

What’s more, there is the index file, which imports all the bricks and makes them available to the React Bricks configuration, so that they can be used in the project.

Other configuration settings can be found in the react-bricks/config.ts file. This file contains important settings that determine the behavior of React Bricks. The _app.tsx file includes additional configurations, such as settings for dark mode.

React Bricks custom brick

Understanding a brick’s structure

Now, let’s have a look for the MyHeroUnit.tsx file. This file contains the code for an example “hero unit” brick.

Here are a few things to note:

  • It is a React component with a TypeScript type of "brick". A brick is a special React component that has a schema property, which we'll see shortly.
  • In the JSX of the component, you can see special visual editing components provided by React Bricks, such as Text, RichText, and Image. These components enable visual editing capabilities! 🪄
  • The schema property is where you can configure the behavior of your brick and define the sidebar controls that allow the content editor to change certain properties of the brick.
  • The padding property, which is configured as a select control in the sidebar, becomes a prop for your React component. It is used to conditionally render different CSS classes.

React Bricks MyHeroUnit

Creating our first brick

Ok, time to create something new!

I'll walk through the process of adding a new brick, specifically a Thumbnail brick. We'll start by creating the brick and then integrate it into your project. So, navigate to the bricks folder in your project and create a new file named Thumbnail.tsx.

React Bricks custom brick

Now open the file and add the following code

import React from 'react'import { types } from 'react-bricks/frontend'const Thumbnail: types.Brick = () => {  return <div className="p-6 text-center">Thumbnail</div>}Thumbnail.schema = {  name: 'Thumbnail',  label: 'Thumbnail',}export default Thumbnail
Enter fullscreen mode Exit fullscreen mode

A peek inside the brick

You see that a brick is a normal React functional component with a schema static property.

The minimal configuration required for a brick includes:

  • name: A unique name for the brick.
  • label: A user-friendly name for the brick shown to the content editors.

Adding bricks to React Bricks’ UI

To integrate the Thumbnail.tsx brick into your project, you need to update the index.ts file in the bricks folder. Open the index.ts file located in the bricks folder and update the file with the following code:

import { types } from 'react-bricks/frontend'import HeroUnit from './custom/MyHeroUnit'import reactBricksUITheme from './react-bricks-ui'import Thumbnail from './Thumbnail'const bricks: types.Theme[] = [  reactBricksUITheme,  {    themeName: 'Custom Theme 1',    categories: [      {        categoryName: 'Hero sections',        bricks: [HeroUnit, Thumbnail],      },    ],  },]export default bricks
Enter fullscreen mode Exit fullscreen mode

This code adds the Thumbnail brick into your project, making it available for use.

Testing block in React Bricks UI

Now that the Thumbnail brick has been integrated, let's test it. Open your terminal and start the project with npm run dev. Now click on the “Edit content” button (or go the the /admin directory in the browser address bar).

After logging in, go to your page and click on the [+] sign below your block.

Choose the “Thumbnail” brick from the options in the right sidebar. A new Thumbnail block will appear on the page.

React Bricks editor

You will notice that even though we added the Thumbnail, it still lacks visual editing capabilities. This is normal, as we haven't added any interactive or editable features to the brick yet.

Adding visual editing

Adding a Text component to our brick

Let’s spice up our brick by adding an editable text component. This will enable users to click on the text and make direct edits within the user interface. We'll start by updating the Thumbnail.tsx file and replacing the static "Thumbnail" text with an editable Text component from React Bricks. Open the Thumbnail.tsx file and replace its content with the following code:

import React from 'react'import { types, Text } from 'react-bricks/frontend'const Thumbnail: types.Brick = () => {  return (    <div className="p-6 text-center">    <Text      propName="title"      renderBlock={({ children }) =>        <h1 className="text-2xl font-bold">          {children}        </h1>      }      placeholder="Type a title..."    />   </div>   )}Thumbnail.schema = {  name: 'thumbnail',  label: 'Thumbnail',}export default Thumbnail
Enter fullscreen mode Exit fullscreen mode

A peek inside the brick

We replaced the static “Thumbnail” text with the Text component from React Bricks, setting the following props on it:

  • propName: This is the name of the prop for the text. In this case, we used "title".
  • renderBlock: A functional component that renders the text. Here, we're rendering the text inside an <h1> tag with some styling.
  • placeholder: This is the hint text displayed when the editable text is empty.

You can also add these two optional boolean props:

  • multiline: Set this to true if you want to allow multiline text.
  • softLineBreak: If set to true, it allows for soft line breaks.

By default, React Bricks' Text component displays "New text" when no default content is provided. We'll change this by setting a custom default text.

We need to modify the Thumbnail.tsx file to include a getDefaultProps function in the brick's schema. This function will return the default properties for the brick when it's added to a page. Open the Thumbnail.tsx file and update the Thumbnail.schema section as follows:

Thumbnail.schema = {  name: 'thumbnail',  label: 'Thumbnail',  getDefaultProps: () => ({    title: 'Hello, world!'  }),}export default Thumbnail
Enter fullscreen mode Exit fullscreen mode

A peek inside the brick

  • getDefaultProps: This function returns an object containing default properties for the brick.
  • title: We set the default value of the title property to 'Hello, world!'. This text will be displayed by default when a new Thumbnail brick is added.

Hit Save, refresh your browser and add a new “Thumbnail” brick to see the changes:

React Bricks editor

If you click on “Hello, world!”, you’ll be able to edit the text. But that’s not all you can do with a brick: we’re only scratching the surface. Let’s dive deeper!

Adding a RichText component

Enhancing the user experience with text formatting is a great way to make your React Bricks project more dynamic. Let’s add a RichText component to the Thumbnail brick, allowing for text formatting such as bold and highlight.

Go back to our old friend Thumbnail.tsx and add the RichText component to the JSX code and the proper default value in the getDefaultProps function , like this:

import React from 'react';import { types, Text, RichText } from 'react-bricks/frontend';const Thumbnail: types.Brick = () => {return (<div className="p-6 text-center">  <Text    propName="title"    renderBlock={({ children }) => (      <h1 className="text-2xl font-bold">{children}</h1>    )}    placeholder="Type a title..."  />  <RichText    propName="description"    renderBlock={({ children }) => (      <p className="text-lg text-gray-500">{children}</p>    )}    placeholder="Type a description"    allowedFeatures={[      types.RichTextFeatures.Bold,      types.RichTextFeatures.Highlight,    ]}  /></div>); };Thumbnail.schema = {  name: 'thumbnail',  label: 'Thumbnail',  getDefaultProps: () => ({    title: 'Hello, world!',    description: 'Lorem ipsum dolor sit amet.',  }),};export default Thumbnail;
Enter fullscreen mode Exit fullscreen mode

You can now edit also the description text below the headline. Additionally, if you select a portion of this text, you have the option to apply bold or highlight styles.

React Bricks editor

A peek at the brick

  • propName: This is set to "description" for the RichText component.
  • renderBlock: This time, it's a paragraph with some styling.
  • placeholder: Text displayed when the editable area is empty.
  • allowedFeatures: Specifies the styling features that are enabled. We've enabled Bold and Highlight.

Changing the highlight color

Let’s override the default rendering of the highlight style in the RichText component to customize its colors.

Open the Thumbnail.tsx file and update the RichText component as follows:

<RichText  propName="description"  renderBlock={({ children }) => (    <p className="text-lg text-gray-500">{children}</p>  )}  placeholder="Type a description"  allowedFeatures={[    types.RichTextFeatures.Bold,    types.RichTextFeatures.Highlight,  ]}  renderHighlight={({ children }) => (    <span className="px-1 rounded bg-blue-200 text-blue-900">{children}</span>  )}/>
Enter fullscreen mode Exit fullscreen mode

React Bricks editor

A peek at the brick

  • renderHighlight: This function overrides the default rendering of the highlight feature.
  • className: We have applied a custom class to the <span> element that wraps the highlighted text. In this example, the background is set to light blue (bg-blue-200), and the text color is set to dark blue (text-blue-900).
  • Pro tip: Use these colors to change the color of the highlight. Just replace the blue-200 and blue-900 parts with other colors from the Tailwind color palette.

Adding an image

A thumbnail is not complete without an image!

To enhance the visual appeal and functionality of the thumbnail, let's add an Image component from React Bricks.

Open Thumbnail.tsx and paste the following code:

import React from 'react';import { types, Text, RichText, Image } from 'react-bricks/frontend';const Thumbnail: types.Brick = () => {return (<div className="my-6 p-6 mx-auto text-center   border rounded-lg max-w-sm shadow-xl"> <Image    propName="image"    alt="Fallback alt tag"    maxWidth={400}    imageClassName="mb-6"    renderWrapper={({children, width, height}) => (      <div className="wrapper">        {children}      </div>    )}  /><Text  propName="title"  renderBlock={({ children }) => (    <h1 className="text-2xl font-bold">{children}</h1>  )}  placeholder="Type a title..."/>  <RichText    propName="description"    renderBlock={({ children }) => (      <p className="text-lg text-gray-500">{children}</p>    )}    placeholder="Type a description"    allowedFeatures={[      types.RichTextFeatures.Bold,      types.RichTextFeatures.Highlight,    ]}  /></div>);};Thumbnail.schema = {  name: 'thumbnail',  label: 'Thumbnail',  getDefaultProps: () => ({  title: 'Hello, world!',  description: 'Lorem ipsum dolor sit amet.',}),  sideEditProps: [],};export default Thumbnail;
Enter fullscreen mode Exit fullscreen mode

A peek at the brick

We added the Image component to add an editable image, setting the following props:

  • propName: Set to "image" for the image prop.
  • alt: A fallback alt tag for the image, if the content editor doesn’t provide a proper alt text.
  • maxWidth: Sets the maximum width of the image. This value is used by the React Bricks servers to optimize the image. The maximum width of the responsive images created will be 2 times this width to comply with retina displays.
  • imageClassName: Adds margin to the bottom of the image.
  • renderWrapper: A function to render a wrapper div around the image. NOTE: IT HAS A WRONG CLASS IN THE EXAMPLE CODE!

Now let’s test the new brick’s functionalities.

React Bricks editor

Look, we now have a rich text field and an image. Cool, isn’t it?

Click on the image placeholder: a popup opens. Select “Replace image” > “Upload” to choose an image file from your computer and upload it. Then you can set an alt tag and a SEO-friendly name for the final part of the URL.

If you don't set any alt tag, the fallback alt specified on the Image component is used instead.

React Bricks editor

Look, I added an image and a descriptive text!

Image optimization

React Bricks introduces an advanced approach to image optimization, ensuring efficient loading and high-quality display across various devices.

React Bricks automatically generates multiple versions of each uploaded image to accommodate different screen resolutions. It creates responsive versions of each image and uses the proper sourceSet to serve the best image based on the screen resolution.

Additionally, it enables lazy loading by leveraging the native browser lazy-load feature, if available. Otherwise, it shows a blurred, low-resolution version of the image when it's outside of the viewport, and replaces it with the full image when it comes into view. This improves the page load performance. But this is something for a separate tutorial, so in the meantime feel free to consult our documentation.

React Bricks docs: Image component

Adding sidebar props

React Bricks allows for dynamic customization of components using sidebar props. To show you how that works, we will add a hasShadow boolean prop to the Thumbnail brick, enabling users to toggle a shadow effect through a checkbox in the sidebar.

So, let’s update —again— our Thumbnail.tsx snippet with the following code:

import React from 'react';import { types, Text, RichText, Image } from 'react-bricks/frontend';interface ThumbnailProps {hasShadow: boolean;}const Thumbnail: types.Brick<ThumbnailProps> = ({ hasShadow }) => {if (!hasShadow) return null;return (<div  className={`my-6 p-6 mx-auto text-center border max-w-sm rounded-lg   ${hasShadow ? 'shadow-xl' : ''}`}>  <Image    propName="image"    alt="Fallback alt tag"    maxWidth={200}    imageClassName="mb-6"  />  <Text    propName="title"    renderBlock={({ children }) => (      <h1 className="text-2xl font-bold">{children}</h1>    )}    placeholder="Type a title..."  />  <RichText    propName="description"    renderBlock={({ children }) => (      <p className="text-lg text-gray-500">{children}</p>    )}    placeholder="Type a description"    allowedFeatures={[      types.RichTextFeatures.Bold,      types.RichTextFeatures.Highlight,    ]}    renderHighlight={({ children }) => (      <span className="px-1 rounded bg-blue-200 text-blue-900">        {children}      </span>    )}  /></div>) }Thumbnail.schema = {  name: 'thumbnail',  label: 'Thumbnail',  getDefaultProps: () => ({    title: 'Hello, world!',    description: 'Lorem ipsum dolor sit amet.',    hasShadow: true  }),  sideEditProps: [    {      name: 'hasShadow',      label: 'Shadow',      type: types.SideEditPropType.Boolean,    },  ],};export default Thumbnail;
Enter fullscreen mode Exit fullscreen mode

Look. the difference may be subtle, but there’s a shadow in the brick and a toggle to turn it on and off.

React Bricks editor

A peek inside the brick

  • ThumbnailProps: TypeScript interface with the hasShadow prop as a boolean.
  • hasShadow: the prop that controls whether the shadow-xl class is applied.
  • SideEditProps: In the schema, we define a sidebar control for hasShadow as a control of type checkbox.

Types of controls

React Bricks supports a variety of control types for side edit props, such as TEXT, NUMBER, DATE, RANGE, BOOLEAN, SELECT, IMAGE and CUSTOM, enabling developers to create highly interactive and customizable UI components.

  • The TextNumberDate, and Range types render the expected HTML5 input control.
  • The Select type, based on the display property, can be rendered as a Select, a Radio button or a Color selection interface.
  • The Image type renders an image upload interface to manage properties such as a background image.
  • The Custom type lets you provide your own component to edit a sidebar prop (component property).

Working with colors

Of course you can also customize colors using sidebar controls. Let’s modify our old friend Thumbnail.tsx with the following code:

import React from 'react'import { types, Text, RichText, Image } from 'react-bricks/frontend'interface ThumbnailProps {hasShadow: booleanbgColor: types.IColor}const Thumbnail: types.Brick<ThumbnailProps> = ({ hasShadow, bgColor }) => {return (if (!hasShadow) return null;<div  className={`my-6 p-6 mx-auto text-center border rounded-lg max-w-sm ${    hasShadow ? 'shadow-xl' : ''  } ${bgColor?.className}`}>  <Image    propName="image"    alt="Fallback alt tag"    maxWidth={200}    imageClassName="mb-6"  />  <Text    propName="title"    renderBlock={({ children }) => (      <h1 className="text-2xl font-bold">{children}</h1>    )}    placeholder="Type a title..."  />  <RichText    propName="description"    renderBlock={({ children }) => (      <p className="text-lg text-gray-500">{children}</p>    )}    placeholder="Type a description"    allowedFeatures={[      types.RichTextFeatures.Bold,      types.RichTextFeatures.Highlight,    ]}    renderHighlight={({ children }) => (      <span className="px-1 rounded bg-blue-200 text-blue-900">        {children}      </span>    )}  /></div>) }Thumbnail.schema = {  name: 'thumbnail',  label: 'Thumbnail',  getDefaultProps: () => ({    title: 'Hello, world!',    description: 'Lorem ipsum dolor sit amet.',    hasShadow: true,    bgColor: { color: '#ffffff', className: 'bg-white' }  }),  sideEditProps: [    {      name: 'hasShadow',      label: 'Shadow',      type: types.SideEditPropType.Boolean,    },    {      name: 'bgColor',      label: 'Background',      type: types.SideEditPropType.Select,      selectOptions: {        display: types.OptionsDisplay.Color,        options: [          {            label: 'White',            value: { color: '#ffffff', className: 'bg-white' },          },          {            label: 'Light blue',            value: { color: '#eff6ff', className: 'bg-blue-50' },          },        ],      },    },  ],}export default Thumbnail
Enter fullscreen mode Exit fullscreen mode

Now you can change the background to gray or white.

React Bricks editor

A peek inside the brick

  • ThumbnailProps** now includes bgColor of type types.IColor.
  • In the sideEditProps we added a select control with display set as types.OptionsDisplay.Color. In this case the values of the options should be objects that have at least a color property, which defines the color to be displayed in the color picking interface. We can include additional properties in this object as well. In this case, we added a className property, which is useful for managing styles with Tailwind CSS..
  • The prop bgColor is then used to apply the selected background color.

Adding a gallery

Creating the Gallery brick

We'll focus on implementing a Gallery brick, using the <Repeater> component and the repeaterItems property in the schema.

To do that, let’s create a new file under /bricks called Gallery.tsx. This file corresponds to the Gallery brick.

import React from 'react';import { types, Repeater } from 'react-bricks/frontend';const Gallery: types.Brick = () => {return (<div className="max-w-5xl mx-auto py-8 px-4">  <h1 className="text-4xl font-bold text-center">Gallery</h1>  <div className="sm:grid grid-cols-3 gap-5">    <Repeater propName="thumbnails" />  </div></div>); };Gallery.schema = {  name: 'gallery',  label: 'Gallery',  getDefaultProps: () => ({    thumbnails: [],  }),  repeaterItems: [    {      name: 'thumbnails',      itemType: 'thumbnail',      itemLabel: 'Thumbnail',      max: 3,    },  ],};export default Gallery;
Enter fullscreen mode Exit fullscreen mode

Pro tip: Remember to import the Gallery brick in the index.ts file just like we did with the Thumbnail brick.

A peek inside the brick

  • The <Repeater> component plays a crucial role in our Gallery brick. It enables us to display a collection of items (in this case, thumbnails) that can be dynamically added, removed, or edited by the user. It should be rendered where you want the repeated items to appear in your layout.
  • propName is essential as it specifies which property in the schema holds the repeatable items.
  • repeaterItems schema defines the characteristics of the repeating items. We used the following props:
    • name: The name of the prop in the schema (e.g., "thumbnails").
    • itemType: The type of brick to be repeated (e.g., "thumbnail").
    • itemLabel: A label for the UI, used in the "Add" menu.
    • max: The maximum number of items allowed (optional).
  • There are many other properties you can use: see the Documentation

React Bricks gallery

You’re ready to push the changes to Github and rebuild the site.

Commit and push changes

You can now commit the changes and push to your Git remote, by using the editor interface or the Git CLI. Once your code is pushed to the remote, if you connected Vercel or Netlify to your repo, it will start the rebuild of your website.

That’s it!

Check the fully functioning website here: https://blog-with-next-two.vercel.app/

Top comments (0)