Custom Style Types
In addition to the default style types that BlockNote offers, you can also make your own custom styles using React components. Take a look at the demo below, in which we add a custom font style to a BlockNote editor, as well as a custom Formatting Toolbar button to set it.
import { BlockNoteSchema, defaultStyleSpecs } from "@blocknote/core";
import "@blocknote/core/fonts/inter.css";
import { BlockNoteView } from "@blocknote/mantine";
import "@blocknote/mantine/style.css";
import {
BasicTextStyleButton,
BlockTypeSelect,
ColorStyleButton,
CreateLinkButton,
FormattingToolbar,
FormattingToolbarController,
ImageCaptionButton,
NestBlockButton,
ReplaceImageButton,
TextAlignButton,
UnnestBlockButton,
useBlockNoteEditor,
useComponentsContext,
useCreateBlockNote,
} from "@blocknote/react";
import { RiText } from "react-icons/ri";
import { Font } from "./Font";
// Our schema with style specs, which contain the configs and implementations for styles
// that we want our editor to use.
const schema = BlockNoteSchema.create({
styleSpecs: {
// Adds all default styles.
...defaultStyleSpecs,
// Adds the Font style.
font: Font,
},
});
// Formatting Toolbar button to set the font style.
const SetFontStyleButton = () => {
const editor = useBlockNoteEditor<
typeof schema.blockSchema,
typeof schema.inlineContentSchema,
typeof schema.styleSchema
>();
const Components = useComponentsContext()!;
return (
<Components.FormattingToolbar.Button
label="Set Font"
mainTooltip={"Set Font"}
icon={<RiText />}
onClick={() => {
const fontName = prompt("Enter a font name") || "Comic Sans MS";
editor.addStyles({
font: fontName,
});
}}
/>
);
};
export default function App() {
// Creates a new editor instance.
const editor = useCreateBlockNote({
schema,
initialContent: [
{
type: "paragraph",
content: "Welcome to this demo!",
},
{
type: "paragraph",
content: [
{
type: "text",
text: "Comic Sans MS",
styles: {
font: "Comic Sans MS",
},
},
{
type: "text",
text: " <- This text has a different font",
styles: {},
},
],
},
{
type: "paragraph",
content:
"Highlight some text to open the Formatting Toolbar and change the font elsewhere",
},
{
type: "paragraph",
},
],
});
return (
<BlockNoteView editor={editor} formattingToolbar={false}>
{/* Replaces the default Formatting Toolbar. */}
<FormattingToolbarController
formattingToolbar={() => (
<FormattingToolbar>
<BlockTypeSelect key={"blockTypeSelect"} />
<ImageCaptionButton key={"imageCaptionButton"} />
<ReplaceImageButton key={"replaceImageButton"} />
<BasicTextStyleButton
basicTextStyle={"bold"}
key={"boldStyleButton"}
/>
<BasicTextStyleButton
basicTextStyle={"italic"}
key={"italicStyleButton"}
/>
<BasicTextStyleButton
basicTextStyle={"underline"}
key={"underlineStyleButton"}
/>
<BasicTextStyleButton
basicTextStyle={"strike"}
key={"strikeStyleButton"}
/>
{/* Adds SetFontStyleButton */}
<SetFontStyleButton />
<TextAlignButton
textAlignment={"left"}
key={"textAlignLeftButton"}
/>
<TextAlignButton
textAlignment={"center"}
key={"textAlignCenterButton"}
/>
<TextAlignButton
textAlignment={"right"}
key={"textAlignRightButton"}
/>
<ColorStyleButton key={"colorStyleButton"} />
<NestBlockButton key={"nestBlockButton"} />
<UnnestBlockButton key={"unnestBlockButton"} />
<CreateLinkButton key={"createLinkButton"} />
</FormattingToolbar>
)}
/>
</BlockNoteView>
);
}
Creating a Custom Style Type
Use the createReactStyleSpec
function to create a custom style type. This function takes two arguments:
function createReactStyleSpec(
styleConfig: CustomStyleConfig,
styleImplementation: ReactStyleImplementation,
);
Let's look at our custom font style from the demo, and go over each field to explain how it works:
export const Font = createReactStyleSpec(
{
type: "font",
propSchema: "string",
},
{
render: (props) => (
<span style={{ fontFamily: props.value }} ref={props.contentRef} />
),
}
);
Style Config (CustomStyleConfig
)
The Style Config describes the shape of your custom style. Use it to specify the type, and whether the style should take a string value:
type CustomStyleConfig = {
type: string;
readonly propSchema: "boolean" | "string";
};
type
Defines the identifier of the custom style.
propSchema
The PropSchema
specifies whether the style can only be toggled ("boolean"
), or whether it can take a string value ("string"
). Having a string value is useful for e.g. setting a color on the style.
In the font style demo, we set this to "string"
so we can store the font family.
Style Implementation (ReactCustomStyleImplementation
)
The Style Implementation defines how the style should be rendered to HTML.
type ReactCustomStyleImplementation = {
render: React.FC<{
value?: string;
contentRef: (node: HTMLElement | null) => void;
}>;
};
render
This is your React component which defines how your custom style should be rendered, and takes two React props:
value:
The string value of the style, this is only available if your style config contains propSchema: "string"
.
contentRef:
A React ref
to mark the editable element.
Note that in contrast to Custom Blocks and Inline Content, the render
function of Custom Styles cannot access React Context or other state. They should be plain React functions analogous to the example.
Adding Custom Style to the Editor
Finally, create a BlockNoteSchema using the definition of your custom style:
const schema = BlockNoteSchema.create({
styleSpecs: {
// enable the default styles if desired
...defaultStyleSpecs,
// Add your own custom style:
font: Font,
},
});
You can then instantiate your editor with this custom schema, as explained on the Custom Schemas page.