← Back to all how-tos

Create a brick

Use links in bricks

Create a LinkButton brick using the React Bricks Link component and editable text.

Estimated time: 5 minRaw Markdown

What you'll build

In this how-to, you'll create a LinkButton brick and use the React Bricks <Link> component to make it clickable.

We'll build it step by step:

  • start with a simple <div> with fixed text
  • turn it into a link with React Bricks <Link>
  • make the label editable with <Text>
  • add sidebar controls for the path and button style

At the end, you'll have a reusable link-style button brick with editable text and configurable settings.

Why use Link in a brick

When you need a link inside a React Bricks brick, you should use the React Bricks Link component: import it from react-bricks/rsc in Next.js App Router projects, or from react-bricks/astro in Astro projects.

import { Link } from 'react-bricks/rsc'

This is important because React Bricks integrates that component with the visual editor.

In practice, this means:

  • links work correctly inside editable bricks
  • editors can select and edit linked content more safely in the admin interface
  • React Bricks can use the underlying platform link behavior correctly

So even though this brick looks like a button, we still use Link, because semantically it navigates to another page or path.

Start with a simple brick

Create a new LinkButton.tsx file and start from a very simple brick:

import { types } from 'react-bricks/rsc'
 
const LinkButton: types.Brick = () => {
  return (
    <div className="inline-block rounded-full bg-indigo-500 px-8 py-3 text-center font-semibold leading-6 text-white">
      Click me
    </div>
  )
}
 
LinkButton.schema = {
  name: 'ws-button',
  label: 'Link Button',
}
 
export default LinkButton

At this point, the brick only renders styled static text.

Turn the brick into a link

Now replace the outer <div> with the React Bricks <Link> component.

Import Link from react-bricks/rsc if you're using Next.js with the App Router, or from react-bricks/astro if you're using Astro:

import { types, Link } from 'react-bricks/rsc'
 
const LinkButton: types.Brick = () => {
  return (
    <Link
      href="/"
      className="inline-block rounded-full bg-indigo-500 px-8 py-3 text-center font-semibold leading-6 text-white"
    >
      Click me
    </Link>
  )
}

This is the key step of the guide.

We are not using a plain <a> tag. We are using the React Bricks Link component so the link works correctly inside the editor too.

Make the button text editable

Now let's replace the fixed "Click me" text with a React Bricks <Text> component.

First, add a props interface:

interface LinkButtonProps {
  buttonText: types.TextValue
}

Then use Text inside the Link:

import { types, Link, Text } from 'react-bricks/rsc'
 
interface LinkButtonProps {
  buttonText: types.TextValue
}
 
const LinkButton: types.Brick<LinkButtonProps> = ({ buttonText }) => {
  return (
    <Link
      href="/"
      className="inline-block rounded-full bg-indigo-500 px-8 py-3 text-center font-semibold leading-6 text-white"
    >
      <Text
        propName="buttonText"
        value={buttonText}
        placeholder="Type an action..."
        renderBlock={({ children }) => <span>{children}</span>}
      />
    </Link>
  )
}

Now the label can be edited directly in the visual editor.

Add a default value in the schema too:

LinkButton.schema = {
  name: 'ws-button',
  label: 'Link Button',
  getDefaultProps: () => ({
    buttonText: 'Click me',
  }),
}

Add a path prop

Hardcoding href="/" is fine for the first step, but now we want editors to choose where the link goes.

Add a path prop:

interface LinkButtonProps {
  buttonText: types.TextValue
  path: string
}

Then use it in the Link:

const LinkButton: types.Brick<LinkButtonProps> = ({ buttonText, path }) => {
<Link href={path} className="inline-block rounded-full bg-indigo-500 px-8 py-3 text-center font-semibold leading-6 text-white">

And add a default value:

getDefaultProps: () => ({
  buttonText: 'Click me',
  path: '/',
}),

Add a sidebar control for the path

Now let's expose path in the React Bricks sidebar:

LinkButton.schema = {
  name: 'ws-button',
  label: 'Link Button',
  getDefaultProps: () => ({
    buttonText: 'Click me',
    path: '/',
  }),
  sideEditProps: [
    {
      name: 'path',
      label: 'Path',
      type: types.SideEditPropType.Text,
    },
  ],
}

This adds a text input in the sidebar, so editors can set the destination of the link without changing code.

Add a button type

Now let's add a second style so editors can choose between a primary and secondary version.

We'll use clsx to switch classes conditionally, so first install it in your project:

pnpm add clsx

Then import it and add a type prop:

import clsx from 'clsx'
import { types, Link, Text } from 'react-bricks/rsc'
 
interface LinkButtonProps {
  buttonText: types.TextValue
  path: string
  type?: 'primary' | 'secondary'
}

Now update the component:

const LinkButton: types.Brick<LinkButtonProps> = ({
  buttonText,
  path,
  type = 'primary',
}) => (
  <Link
    href={path}
    className={clsx(
      'inline-block text-center font-semibold leading-6 transition-colors rounded-full px-8 py-3 border',
      type === 'primary'
        ? 'text-white bg-indigo-500 hover:bg-indigo-500/90 border-indigo-500'
        : 'text-indigo-500 bg-indigo-50 hover:bg-indigo-50/50 border-indigo-50 hover:border-indigo-200'
    )}
  >
    <Text
      propName="buttonText"
      value={buttonText}
      placeholder="Type an action..."
      renderBlock={({ children }) => <span>{children}</span>}
    />
  </Link>
)

And add the default:

getDefaultProps: () => ({
  buttonText: 'Click me',
  type: 'primary',
  path: '/',
}),

Add the sidebar control for type

Finally, add a second sidebar control:

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' },
      ],
    },
  },
]

Now editors can:

  • change the button label inline
  • set the destination path from the sidebar
  • switch between primary and secondary styles

Final code

Your full LinkButton.tsx file should look like this:

import { types, Link, Text } from 'react-bricks/rsc'
import clsx from 'clsx'
 
interface LinkButtonProps {
  buttonText: types.TextValue
  path: string
  type?: 'primary' | 'secondary'
}
 
const LinkButton: types.Brick<LinkButtonProps> = ({
  buttonText,
  path,
  type = 'primary',
}) => (
  <Link
    href={path}
    className={clsx(
      'inline-block text-center font-semibold leading-6 transition-colors rounded-full px-8 py-3 border',
      type === 'primary'
        ? 'text-white bg-indigo-500 hover:bg-indigo-500/90 border-indigo-500'
        : 'text-indigo-500 bg-indigo-50 hover:bg-indigo-50/50 border-indigo-50 hover:border-indigo-200'
    )}
  >
    <Text
      propName="buttonText"
      value={buttonText}
      placeholder="Type an action..."
      renderBlock={({ children }) => <span>{children}</span>}
    />
  </Link>
)
 
LinkButton.schema = {
  name: 'ws-button',
  label: 'Link Button',
  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

What's next

You now have a brick that combines link behavior, editable text, and sidebar controls.

From here, you can use the same pattern for cards, CTAs, navigation items, or buttons nested inside more complex bricks.