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. Ifvalues
is not defined, BlockNote assumes the prop can be any value ofPrimitiveType
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.