Docs
Custom Inline Content

Custom Inline Content Types

In addition to the default inline content types that BlockNote offers, you can also make your own custom inline content using React components. Take a look at the demo below, in which we add a custom mention tag to a BlockNote editor, as well as a custom Suggestion Menu to insert it.

import {
  BlockNoteSchema,
  defaultInlineContentSpecs,
  filterSuggestionItems,
} from "@blocknote/core";
import "@blocknote/core/fonts/inter.css";
import {
  BlockNoteView,
  DefaultReactSuggestionItem,
  SuggestionMenuController,
  useCreateBlockNote,
} from "@blocknote/react";
import "@blocknote/react/style.css";
 
import { Mention } from "./Mention";
 
// Our schema with inline content specs, which contain the configs and
// implementations for inline content  that we want our editor to use.
const schema = BlockNoteSchema.create({
  inlineContentSpecs: {
    // Adds all default inline content.
    ...defaultInlineContentSpecs,
    // Adds the mention tag.
    mention: Mention,
  },
});
 
// Function which gets all users for the mentions menu.
const getMentionMenuItems = (
  editor: typeof schema.BlockNoteEditor
): DefaultReactSuggestionItem[] => {
  const users = ["Steve", "Bob", "Joe", "Mike"];
 
  return users.map((user) => ({
    title: user,
    onItemClick: () => {
      editor.insertInlineContent([
        {
          type: "mention",
          props: {
            user,
          },
        },
        " ", // add a space after the mention
      ]);
    },
  }));
};
 
export function App() {
  const editor = useCreateBlockNote({
    schema,
    initialContent: [
      {
        type: "paragraph",
        content: "Welcome to this demo!",
      },
      {
        type: "paragraph",
        content: [
          {
            type: "mention",
            props: {
              user: "Steve",
            },
          },
          {
            type: "text",
            text: " <- This is an example mention",
            styles: {},
          },
        ],
      },
      {
        type: "paragraph",
        content: "Press the '@' key to open the mentions menu and add another",
      },
      {
        type: "paragraph",
      },
    ],
  });
 
  return (
    <BlockNoteView editor={editor}>
      {/* Adds a mentions menu which opens with the "@" key */}
      <SuggestionMenuController
        triggerCharacter={"@"}
        getItems={async (query) =>
          // Gets the mentions menu items
          filterSuggestionItems(getMentionMenuItems(editor), query)
        }
      />
    </BlockNoteView>
  );
}
 
export default App;
 

Creating a Custom Inline Content Type

Use the createReactInlineContentSpec function to create a custom inline content type. This function takes two arguments:

function createReactInlineContentSpec(
  blockConfig: CustomInlineContentConfig,
  blockImplementation: ReactInlineContentImplementation,
);

Let's look at our custom mentions tag from the demo, and go over each field to explain how it works:

const Mention = createReactInlineContentSpec(
  {
    type: "mention",
    propSchema: {
      user: {
        default: "Unknown",
      },
    },
    content: "none",
  } as const,
  {
    render: (props) => (
      ...
    ),
  }
);

Inline Content Config (CustomInlineContentConfig)

The Inline Content Config describes the shape of your custom inline content. Use it to specify the type, properties (props) and content your custom inline content should support:

type CustomInlineContentConfig = {
  type: string;
  content: "styled" | "none";
  readonly propSchema: PropSchema;
};

type

Defines the identifier of the custom inline content.

content

styled if your custom inline content should contain StyledText, none if not.

In the mentions demo, we want each mention to be a single, non-editable element, so we set it to "none".

propSchema

The PropSchema specifies the props that the inline content supports. Inline content props (properties) are data stored with your inline content in the document, and can be used to customize its appearance or behavior.

type PropSchema<
  PrimitiveType extends "boolean" | "number" | "string"
> = Record<
  string,
  {
    default: PrimitiveType;
    values?: PrimitiveType[];
  }
>

[key: string] is the name of the prop, and the value is an object with two fields:

  • default: Specifies the prop's default value

  • values (optional): Specifies an array of values that the prop can take, for example, to limit the value to a list of pre-defined strings. If values is not defined, BlockNote assumes the prop can be any value of PrimitiveType

In the mentions demo, we add a user prop for the user that's being mentioned.

Inline Content Implementation (ReactCustomInlineContentImplementation)

The Inline Content Implementation defines how the inline content should be rendered to HTML.

type ReactCustomInlineContentImplementation = {
  render: React.FC<{
    inlineContent: InlineContent;
    contentRef?: (node: HTMLElement | null) => void;
  }>;
};

render

This is your React component which defines how your custom inline content should be rendered, and takes three React props:

inlineContent: The inline content that should be rendered. Its type and props will match the type and PropSchema defined in the Inline Content Config.

contentRef: A React ref you can use to mark which element in your inline content is editable, this is only available if your inline content config contains content: "styled".

Note that since inline content is, by definition, inline, your component should also return an HTML inline element.

Adding Custom Inline Content to the Editor

Finally, create a BlockNoteSchema using the definition of your custom inline content:

const schema = BlockNoteSchema.create({
  inlineContentSpecs: {
    // enable the default inline content if desired
    ...defaultInlineContentSpecs,
 
    // Add your own custom inline content:
    mention: Mention,
  },
});

You can then instantiate your editor with this custom schema, as explained on the Custom Schemas page.