Templates & ExamplesExamples & GuidesCustom Components in Rich Text

Custom Components in Rich Text

Learn how to use custom components within rich text blocks.

Custom components in rich text allows you to extend beyond the basic rich text nodes. This can enable you to embed things like:

  • Tweets

  • Interactive code blocks

  • Callouts, or any other thing you can imagine…

In this guide, we’ll walk you through creating a component that fits your need, all the way to rendering it in your website.

Create the component1

To create a new component, we’ll go to somewhere in our editor and write /component. We’ll give it a name, and add some data into it.

In this case, we’ll create a “Tweet” component, we’ll add an ID block (required), and therefore Hide this component (to skip the “required” validation. Learn more).

Create a Rich Text block, and add our new component to “Component types”2

Next, we’ll create a rich text block. You’d typically have this within a collection, but you can also drop it inside a regular document.

In this video, we also go ahead and add a tweet id for the tweet we want to embed.

Set up the code environment3

Let’s get BaseHub connected to a new Next.js App.

pnpm create next-app

We install basehub:

pnpm install basehub

Now, we add the basehub scripts so the codegen runs before next dev and next build. In package.json:

  "scripts": {
    "dev": "basehub dev & next dev --turbopack",
    "build": "basehub && next build",
    "start": "next start",
    "lint": "next lint"
  },
note:

Note: this snippet includes just package.json > scripts; you should keep the rest of the file as is.

We then add our BASEHUB_TOKEN to .env.local:

BASEHUB_TOKEN="<grab-this-from-your-dash>"

And finally, we run the dev server:

pnpm run dev

Query the rich text block, using blocks 4

Let’s now create our first query, using Pump, to get the content in our Rich Text. Over in app/page.tsx, let’s replace everything with the following:

import { Pump } from "basehub/react-pump";

export default function Home() {
  return (
    <Pump
      queries={[
        {
          indexPage: {
            title: {
              json: {
                content: true,
                blocks: {
                  on_BlockDocument: {
                    __typename: true,
                    _id: true,
                  },
                  on_TweetComponent: {
                    id: true,
                  },
                },
              },
            },
          },
        },
      ]}
    >
      {async ([{ indexPage }]) => {
        "use server";
        return <pre>{JSON.stringify(indexPage, null, 2)}</pre>;
      }}
    </Pump>
  );
}

Now, when navigating to http://localhost:3000, you should see this in your screen:

Render it using <RichText /> 5

Let’s now use the <RichText /> react component to handle our Tweet component. We import the component:

import { RichText } from 'basehub/react-rich-text'

And use it:

async ([{ indexPage }]) => {
  "use server"
  return (
    <RichText
      content={indexPage.title.json.content}
      blocks={indexPage.title.json.blocks}
      components={{
        TweetComponent: ({ id }) => {
          return <div>Render tweet: {id}</div>
        },
      }}
    />
  )
}

All together, that file now looks like this:

import { Pump } from "basehub/react-pump";
import { RichText } from "basehub/react-rich-text";

export default function Home() {
  return (
    <Pump
      queries={[
        {
          indexPage: {
            title: {
              json: {
                content: true,
                blocks: {
                  on_BlockDocument: {
                    __typename: true,
                    _id: true,
                  },
                  on_TweetComponent: {
                    id: true,
                  },
                },
              },
            },
          },
        },
      ]}
    >
      {async ([{ indexPage }]) => {
        "use server";
        return (
          <RichText
            content={indexPage.title.json.content}
            blocks={indexPage.title.json.blocks}
            components={{
              TweetComponent: ({ id }) => {
                return <div>Render tweet: {id}</div>;
              },
            }}
          />
        );
      }}
    </Pump>
  );
}

Bonus: use react-tweet to render the tweet6

Up until this point, you can already handle your own custom logic within those components. In our case, we’ll install react-tweet to render our tweet.

pnpm i react-tweet

And then adjust some things:

import { Tweet } from "react-tweet"

// the rest stays as is

TweetComponent: ({ id }) => {
  return <Tweet id={id} />
}

And the result is:

Not the prettiest, but a good foundation to build powerful rich texts!

Wrapping Up

That’s all for this guide! Let us know if you have any questions or suggestions in our Help Center.

Last updated 17 seconds ago