Docs
Custom Styles

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 {
  BasicTextStyleButton,
  BlockTypeSelect,
  ColorStyleButton,
  CreateLinkButton,
  FormattingToolbar,
  FormattingToolbarController,
  ImageCaptionButton,
  NestBlockButton,
  ReplaceImageButton,
  TextAlignButton,
  UnnestBlockButton,
  useBlockNoteEditor,
  useComponentsContext,
  useCreateBlockNote,
} from "@blocknote/react";
import { BlockNoteView } from "@blocknote/mantine";
import "@blocknote/mantine/style.css";
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
      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.