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.
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;
draggable?: boolean;
};
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 content
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[];
}
| {
default: undefined;
type: PrimitiveType;
values?: PrimitiveType[];
}
>;
[key: string]
is the name of the prop. If you want it to have a default value, it should be defined as an object with the following properties:
-
default:
Specifies the prop's default value, from whichPrimitiveType
is inferred. -
values?:
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
.
If you do not want the prop to have a default value, you can define it as an object with the following properties:
-
default:
Leftundefined
, as there is no default value. -
type:
SpecifiesPrimitiveType
that the prop can be set to, since the default value isundefined
and cannot be inferred from. -
values?:
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.
draggable?:
Whether the inline content should be draggable.
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;
draggable?: boolean;
}>;
};
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 Reactref
you can use to mark which element in your inline content is editable, this is only available if your inline content config containscontent: "styled"
. -
draggable:
Specifies whether the inline content can be dragged within the editor. If set totrue
, the inline content will be draggable. Defaults tofalse
if not specified. If this is true, you should adddata-drag-handle
to the DOM element that should function as the drag handle.
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.