--- title: Nesting bricks with Repeater category: Custom bricks order: 13 status: published summary: Nest LinkButton bricks inside a TextImage brick using the React Bricks Repeater component. estimatedTime: 5 min keywords: repeater nested bricks repeateritems nesting repeat --- ## What you'll build In this how-to, you'll nest `LinkButton` bricks inside a `TextImage` brick using the React Bricks `` component. The goal is to render a row of buttons below the text part of `TextImage`. We'll do it in 2 steps: - first, prepare the `LinkButton` brick so it can be reused inside another brick - then add a `Repeater` to `TextImage` ## The starting point Suppose you already have: - a `TextImage` brick, like the one used in the first how-tos - a `LinkButton` brick, like the one used in the latest guides Now we want `TextImage` to render repeated buttons below its rich text. ## Step 1: prepare `LinkButton` Before using `LinkButton` inside another brick, we need 2 small changes. ### Export the props interface First, export the props interface: ```tsx {1} export interface ButtonProps { buttonText: types.TextValue path: string type?: 'primary' | 'secondary' } ``` This is useful because `TextImage` will import that interface for correct typing. ### Hide the brick from the add menu Now set `hideFromAddMenu: true` in the schema: ```tsx {4} LinkButton.schema = { name: 'ws-button', label: 'Button', hideFromAddMenu: true, // ... } ``` We do this because the button is not meant to be added directly to a page anymore. Instead, it will be added only inside other bricks through a repeater. ## The updated `LinkButton` Your `LinkButton.tsx` file should now look like this: ```tsx {4,36} import { types, Link, Text } from 'react-bricks/rsc' import clsx from 'clsx' export interface ButtonProps { buttonText: types.TextValue path: string type?: 'primary' | 'secondary' } const LinkButton: types.Brick = ({ buttonText, path, type = 'primary', }) => ( {children}} /> ) LinkButton.schema = { name: 'ws-button', label: 'Button', hideFromAddMenu: true, getDefaultProps: () => ({ buttonText: 'Click me', type: 'primary', path: '/', }), sideEditProps: [ { name: 'path', label: 'Path', type: types.SideEditPropType.Text, }, { name: 'type', label: 'Type', type: types.SideEditPropType.Select, selectOptions: { display: types.OptionsDisplay.Radio, options: [ { value: 'primary', label: 'Primary' }, { value: 'secondary', label: 'Secondary' }, ], }, }, ], } export default LinkButton ``` ## Step 2: update `TextImage` Now let's move to the `TextImage` brick. First, import `Repeater` and `ButtonProps`. If you're using Next.js with the App Router, import `Repeater` from `react-bricks/rsc`. If you're using Astro, import it from `react-bricks/astro`. For the button props, import the exported interface from your `LinkButton` file. ```tsx {2} import { Image, Link, Repeater, RichText, Text, types } from 'react-bricks/rsc' import type { ButtonProps } from './LinkButton' ``` ## Add the `buttons` prop Now update the `TextImage` interface: ```tsx {5} interface TextImageProps { title: types.TextValue description: types.TextValue image: types.IImageSource buttons: types.RepeaterItems } ``` `types.RepeaterItems` means that this prop contains repeated items whose props match the `ButtonProps` interface. Then read `buttons` from the component props: ```tsx {5} const TextImage: types.Brick = ({ title, description, image, buttons, }) => { ``` ## Add the `Repeater` Below the `RichText`, add a `Repeater`: ```tsx {21-25}
(

{children}

)} /> (

{children}

)} allowedFeatures={[types.RichTextFeatures.Bold, types.RichTextFeatures.Link]} />
{items}
} />
``` ## Explain the `Repeater` props Here is what each prop does: - `propName="buttons"` binds the repeater to the `buttons` prop - `items={buttons}` passes the current repeater items from the brick props - `renderWrapper` tells React Bricks how to render the container around the repeated items ## What `renderWrapper` does The `renderWrapper` function receives the rendered repeated items and lets you decide how they should be wrapped in the layout. The wrapper is rendered only when there is at least one repeated item. In this example: ```tsx renderWrapper={(items) =>
{items}
} ``` we wrap all repeated buttons inside a `div` with: - `flex` to place them in a row - `gap-4` to add spacing between buttons - `mt-6` to add space above the button row So `renderWrapper` is where you define the layout for the repeated bricks as a group, without rendering an empty wrapper when there are no items. ## Add `repeaterItems` to the schema The last step is telling React Bricks which brick type is allowed inside this repeater. Add this to the `TextImage` schema: ```tsx {7-13} TextImage.schema = { name: 'text-image', label: 'Text Image', // ... repeaterItems: [ { name: 'buttons', itemType: 'ws-button', max: 2, }, ], } ``` ## Explain `repeaterItems` Each object inside `repeaterItems` configures one repeater field. Here: - `name`: the name of the repeater prop on the component, in this case `buttons` - `itemType`: the brick type that can be repeated inside that repeater, in this case `ws-button` - `max`: the maximum number of repeated items allowed So this configuration means: - the repeater is bound to `buttons` - each repeated item must be a `ws-button` - editors can add up to 2 buttons An `repeaterItems` object can also include `min` to require a minimum number of items. And more generally, a repeater is not limited to just one brick type: React Bricks also lets you configure repeaters that allow multiple kinds of bricks using the `items` prop. For the full reference, see the React Bricks docs: [The schema's repeaterItems property](https://docs.reactbricks.com/api-reference/visual-components/repeater/#the-schemas-repeateritems-property) ## Final `TextImage` example Your `TextImage.tsx` file could look like this: ```tsx {2,8,15,53-59,85-91} import { Image, Link, Repeater, RichText, Text, types } from 'react-bricks/rsc' import type { ButtonProps } from './LinkButton' interface TextImageProps { title: types.TextValue description: types.TextValue image: types.IImageSource buttons: types.RepeaterItems } const TextImage: types.Brick = ({ title, description, image, buttons, }) => { return (
(

{children}

)} /> (

{children}

)} allowedFeatures={[ types.RichTextFeatures.Bold, types.RichTextFeatures.Link, ]} renderLink={({ children, href, target, rel }) => ( {children} )} /> (
{items}
)} />
Image
) } TextImage.schema = { name: 'text-image', label: 'Text Image', getDefaultProps: () => ({ title: 'Thick as a brick', description: 'Another brick in the wall', }), repeaterItems: [ { name: 'buttons', itemType: 'ws-button', max: 2, }, ], } export default TextImage ``` Your `TextImage` brick now contains nested `LinkButton` bricks.