Create a brick
Add an editable image
Add a visually editable image to your custom brick and place it beside the text.
What you'll build
In this how-to, you'll add a visually editable image to a TextImage brick using the React Bricks <Image> component.
You'll:
- add an
imageprop to the component interface - import
Imagefrom the React Bricks package for your platform - wrap the brick in a
container - create a two-column grid with text on the left and image on the right
At the end, editors will be able to upload and replace the image directly in the visual editor.
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 { Link, RichText, Text, types } from 'react-bricks/rsc'
interface TextImageProps {
title: types.TextValue
description: types.TextValue
}
const TextImage: types.Brick<TextImageProps> = ({ title, description }) => {
return (
<>
<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>
)}
/>
</>
)
}
TextImage.schema = {
name: 'text-image',
label: 'Text Image',
getDefaultProps: () => ({
title: 'Thick as a brick',
description: 'Another brick in the wall',
}),
}
export default TextImageNow we'll add an image and place the content in two columns.
Add the image prop
First, import Image from react-bricks/rsc if you're using Next.js with the App Router, or from react-bricks/astro if you're using Astro, and add a new image prop to the interface:
import { Image, Link, RichText, Text, types } from 'react-bricks/rsc'
interface TextImageProps {
title: types.TextValue
description: types.TextValue
image: types.IImageSource
}Then read image from the component props:
const TextImage: types.Brick<TextImageProps> = ({
title,
description,
image,
}) => {types.IImageSource is the type React Bricks uses for editable image fields.
Add the container and grid layout
Now wrap the brick in a container and use a two-column grid:
return (
<div className="container">
<div className="grid lg:grid-cols-2 gap-12">
<div>{/* current text content goes here */}</div>
<div>{/* image goes here */}</div>
</div>
</div>
)This gives you:
- text on the left
- image on the right on large screens
- a single-column layout on smaller screens
Add the image component
Inside the grid, create one <div> for the text and one for the image:
<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>Here:
propName="image"binds the editor field to theimagepropsource={image}passes the current image valuealt="Image"is the fallback alt textmaxWidth={800}helps React Bricks optimize the generated imagesaspectRatio={16 / 9}keeps the image shape consistent
Why maxWidth matters
React Bricks uses the maxWidth value to generate optimized responsive images.
That means it can create image sizes appropriate for the actual space used by the brick, instead of serving a larger image than necessary.
Final code
Your full TextImage.tsx file should now 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 TextImageTry it in the editor
Go back to the visual editor and add or edit the Text Image brick.
Now you can:
- click the image placeholder to upload an image
- replace the image directly in the editor
- keep editing the title and description inline
- see the layout switch to two columns on larger screens
If you don't set an alt text in the editor, the fallback "Image" value is used.
What's next
Your brick now combines editable text, rich text, and an editable image.
The next step is usually to add sidebar controls for layout and appearance, such as toggles, select options, or alignment settings.