← Back to all how-tos

Create a brick

Add a sidebar control

Add a sidebar control to let editors choose whether the image appears on the left or right.

Estimated time: 4 minRaw Markdown

What you'll build

In this how-to, you'll add a sidebar control to the TextImage brick so editors can choose whether the image is shown on the left or on the right.

You'll:

  • add an imageSide prop to the component interface
  • use clsx to conditionally change the image column order
  • add sideEditProps to the schema
  • set a default value for the new prop

At the end, editors will be able to switch the image position from the React Bricks sidebar.

Start from the previous example

If you're starting from the brick used in the previous how-to, your TextImage should look like this:

import { Image, Link, RichText, Text, types } from 'react-bricks/rsc'
 
interface TextImageProps {
  title: types.TextValue
  description: types.TextValue
  image: types.IImageSource
}
 
const TextImage: types.Brick<TextImageProps> = ({
  title,
  description,
  image,
}) => {
  return (
    <div className="container">
      <div className="grid lg:grid-cols-2 gap-12">
        <div>
          <Text
            propName="title"
            value={title}
            placeholder="Type a title..."
            renderBlock={({ children }) => (
              <h2 className="text-3xl font-extrabold">{children}</h2>
            )}
          />
 
          <RichText
            propName="description"
            value={description}
            placeholder="Type a description..."
            renderBlock={({ children }) => (
              <p className="text-lg text-slate-600">{children}</p>
            )}
            allowedFeatures={[
              types.RichTextFeatures.Bold,
              types.RichTextFeatures.Link,
            ]}
            renderBold={({ children }) => (
              <b className="text-pink-500">{children}</b>
            )}
            renderLink={({ children, href, target, rel }) => (
              <Link
                href={href}
                target={target}
                rel={rel}
                className="text-sky-500 hover:text-sky-600 transition-colors"
              >
                {children}
              </Link>
            )}
          />
        </div>
 
        <div>
          <Image
            propName="image"
            source={image}
            alt="Image"
            maxWidth={800}
            aspectRatio={16 / 9}
          />
        </div>
      </div>
    </div>
  )
}
 
TextImage.schema = {
  name: 'text-image',
  label: 'Text Image',
 
  getDefaultProps: () => ({
    title: 'Thick as a brick',
    description: 'Another brick in the wall',
  }),
}
 
export default TextImage

Add the imageSide prop

First, add a new prop to the interface:

interface TextImageProps {
  title: types.TextValue
  description: types.TextValue
  image: types.IImageSource
  imageSide: 'left' | 'right'
}

Then read it from the component props:

const TextImage: types.Brick<TextImageProps> = ({
  title,
  description,
  image,
  imageSide,
}) => {

This prop will store the editor's choice for the image position.

Use clsx for conditional classes

Before using clsx, install it in your project:

pnpm add clsx

To conditionally change the order of the image column, import clsx:

import clsx from 'clsx'

Now update the <div> that wraps the image:

<div className={clsx({ 'order-first': imageSide === 'left' })}>
  <Image
    propName="image"
    source={image}
    alt="Image"
    maxWidth={800}
    aspectRatio={16 / 9}
  />
</div>

If imageSide === 'left', the order-first class is applied, so on large screens the image becomes the first column.

If imageSide === 'right', no extra class is added, so the text stays first and the image stays on the right.

Add sideEditProps to the schema

Now let's add a sidebar control to the schema:

TextImage.schema = {
  name: 'text-image',
  label: 'Text Image',
 
  getDefaultProps: () => ({
    title: 'Thick as a brick',
    description: 'Another brick in the wall',
    imageSide: 'right',
  }),
 
  sideEditProps: [
    {
      name: 'imageSide',
      label: 'Image Side',
      type: types.SideEditPropType.Select,
      selectOptions: {
        display: types.OptionsDisplay.Radio,
        options: [
          { value: 'left', label: 'Left' },
          { value: 'right', label: 'Right' },
        ],
      },
    },
  ],
}

sideEditProps defines controls shown in the React Bricks sidebar for the selected brick.

Each object in this array describes one editable setting:

  • name: the prop name to update on the component
  • label: the label shown in the sidebar UI
  • type: the kind of control to render

In this case, type: types.SideEditPropType.Select means we want to render a select-style control.

Inside selectOptions:

  • display: types.OptionsDisplay.Radio tells React Bricks to show the options as radio buttons
  • options defines the available choices
  • each option has a value, which is stored in the prop, and a label, which is shown to the editor

So when the editor picks Left, the prop becomes imageSide: 'left'. When the editor picks Right, the prop becomes imageSide: 'right'.

Set the default value

We also added:

imageSide: 'right'

inside getDefaultProps.

This means new TextImage bricks will show the image on the right by default.

Final code

Your full TextImage.tsx file should now look like this:

import clsx from 'clsx'
import { Image, Link, RichText, Text, types } from 'react-bricks/rsc'
 
interface TextImageProps {
  title: types.TextValue
  description: types.TextValue
  image: types.IImageSource
  imageSide: 'left' | 'right'
}
 
const TextImage: types.Brick<TextImageProps> = ({
  title,
  description,
  image,
  imageSide,
}) => {
  return (
    <div className="container">
      <div className="grid lg:grid-cols-2 gap-12">
        <div>
          <Text
            propName="title"
            value={title}
            placeholder="Type a title..."
            renderBlock={({ children }) => (
              <h2 className="text-3xl font-extrabold">{children}</h2>
            )}
          />
 
          <RichText
            propName="description"
            value={description}
            placeholder="Type a description..."
            renderBlock={({ children }) => (
              <p className="text-lg text-slate-600">{children}</p>
            )}
            allowedFeatures={[
              types.RichTextFeatures.Bold,
              types.RichTextFeatures.Link,
            ]}
            renderBold={({ children }) => (
              <b className="text-pink-500">{children}</b>
            )}
            renderLink={({ children, href, target, rel }) => (
              <Link
                href={href}
                target={target}
                rel={rel}
                className="text-sky-500 hover:text-sky-600 transition-colors"
              >
                {children}
              </Link>
            )}
          />
        </div>
 
        <div className={clsx({ 'order-first': imageSide === 'left' })}>
          <Image
            propName="image"
            source={image}
            alt="Image"
            maxWidth={800}
            aspectRatio={16 / 9}
          />
        </div>
      </div>
    </div>
  )
}
 
TextImage.schema = {
  name: 'text-image',
  label: 'Text Image',
 
  getDefaultProps: () => ({
    title: 'Thick as a brick',
    description: 'Another brick in the wall',
    imageSide: 'right',
  }),
 
  sideEditProps: [
    {
      name: 'imageSide',
      label: 'Image Side',
      type: types.SideEditPropType.Select,
      selectOptions: {
        display: types.OptionsDisplay.Radio,
        options: [
          { value: 'left', label: 'Left' },
          { value: 'right', label: 'Right' },
        ],
      },
    },
  ],
}
 
export default TextImage

Try it in the editor

Go back to the visual editor and select the Text Image brick.

Now, in the sidebar, you'll see an Image Side control with two radio options:

  • Left
  • Right

When you switch between them, the image column changes position.

What's next

Your brick now has a sidebar control that changes the layout without editing the code.

From here, you can add more sidebar props for spacing, colors, alignment, or image aspect ratio.