Create a brick
Use links in bricks
Create a LinkButton brick using the React Bricks Link component and editable text.
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 LinkButtonAt 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 clsxThen 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 LinkButtonWhat'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.