Skip to content
On this page

Block Types & Properties

A block's type affects how it looks and behaves in the editor. Each type also comes with its own set of properties, each having a string value, which further affect the block's appearance and behaviour.

Built-In Block Types

BlockNote includes a number of built-in block types, each with their own set of properties. You can see how they look, both in the editor, and in code using Block objects:

Paragraph

Appearance

image

Type & Props

typescript
type ParagraphBlock = {
  id: string;
  type: "paragraph";
  props: DefaultBlockProps;
  content: InlineContent[];
  children: Block[];
};

Heading

Appearance

image

Type & Props

typescript
type HeadingBlock = {
  id: string;
  type: "heading";
  props: {
    level: "1" | "2" | "3" = "1";
  } & DefaultBlockProps;
  content: InlineContent[];
  children: Block[];
};

level: The heading level, representing a title (level: "1"), heading (level: "2"), and subheading (level: "3").

Bullet List Item

Appearance

image

Type & Props

typescript
type BulletListItemBlock = {
  id: string;
  type: "bulletListItem";
  props: DefaultBlockProps;
  content: InlineContent[];
  children: Block[];
};

Numbered List Item

Appearance

image

Type & Props

typescript
type NumberedListItemBlock = {
  id: string;
  type: "numberedListItem";
  props: DefaultBlockProps;
  content: InlineContent[];
  children: Block[];
};

Default Block Properties

While each type of block can have its own set of properties, there are some properties that all built-in block types have by default, which you can find in the definition for DefaultBlockProps:

typescript
type DefaultBlockProps = {
  backgroundColor: string = "default";
  textColor: string = "default";
  textAlignment: "left" | "center" | "right" | "justify" = "left";
};

backgroundColor: The background color of the block, which also applies to nested blocks.

textColor: The text color of the block, which also applies to nested blocks.

textAlignment: The text alignment of the block.

Custom Block Types

In addition to the default block types that BlockNote offers, you can also make your own custom blocks. Take a look at the demo below, in which we add a custom block containing an image and caption to a BlockNote editor, as well as a custom Slash Menu Item to insert it.

Block Config Objects

To define a custom block type, we use a ReactBlockConfig object, for which you can see the definition below:

typescript
type PropSchema = Record<
  string,
  {
    default: string;
    values?: string[];
  };
>

type ReactBlockConfig<
  Type extends string,
  PSchema extends PropSchema,
  ContainsInlineContent extends boolean,
  BSchema extends BlockSchema
> = {
  type: Type;
  propSchema: PSchema;
  containsInlineContent: ContainsInlineContent;
  render: (props: {
    block: Block<BSchema>,
    editor: BlockNoteEditor<BSchema>
  }) => JSX.Element;
};

To make sure we understand what's going on here, let's look at the BlockConfig we defined for our custom image block in the demo, and go over in-depth for what each field is for.

typescript
const ImageBlockConfig = {
  type: "image",
  propSchema: {
    src: {
      default: "https://via.placeholder.com/1000",
    },
  },
  containsInlineContent: true,
  render: ({ block }) => (
    <div
      style={{
        display: "flex",
        flexDirection: "column",
      }}
    >
      <img
        style={{
          width: "100%",
        }}
        src={block.props.src}
        alt={"Image"}
        contentEditable={false}
      />
      <InlineContent />
    </div>
  )
};

type

This is the simplest field in a BlockConfig, and just defines the name of the block, in this case, image.

propSchema

This is an object which defines the props that the block should have. In this case, we want the block to have a src prop for the URL of the image, so we add a src key. We also want basic styling options for the image block, so we also add the Default Block Properties using defaultProps. The value of each key is an object with a mandatory default field and an optional values field:

default: Stores the prop's default value, so we use a placeholder image URL for src if no URL is provided.

values: Stores an array of strings that the prop can take. If values is not defined, BlockNote assumes the prop can be any string, which makes sense for src, since it can be any image URL.

containsInlineContent

As we saw in Block Objects, blocks can contain editable rich text which is represented as Inline Content. The containsInlineContent field allows your custom block to contain an editable rich-text field. For the custom image block, we use an inline content field to create our caption, so it's set to true.

render

This is a React component which defines how your custom block should be rendered in the editor, and takes two props:

block: The block that should be rendered.

editor: The BlockNote editor instance that the block is in.

For our custom image block, we use a parent div which contains the image and caption. Since block will always be an image block, we also know it contains a src prop, and can pass it to the child img element.

But what's this InlineContent component? Since we set containsInlineContent to true, it means we want to include an editable rich-text field somewhere in the image block. You should use the InlineContent component to represent this field in your render component. Since we're using it to create our caption, we add it below the img element.

While the InlineContent component can be put anywhere inside the component you pass to render, you should make sure to only have one. If containsInlineContent is set to false, render shouldn't contain any.

Adding Custom Blocks to the Editor

After creating BlockConfigs for all of our custom blocks, we need to convert them into BlockSpecs. A BlockSpec just tells BlockNote how your custom block should be defined internally, so we don't need to know much about it. We just need to convert our BlockConfig to a BlockSpec using the createReactBlockSpec function:

typescript
function createReactBlockSpec(blockConfig: BlockConfig): BlockSpec {...};

Now, all we need to do is pass it to the editor using the blockSchema option, which tells BlockNote which blocks to use. Let's again look at the image block from the demo as an example:

typescript
const ImageBlock = createReactBlockSpec(ImageBlockConfig);

...

// Creates a new editor instance.
const editor: BlockNoteEditor<
  DefaultBlockSchema & { image: typeof ImageBlock }
> | null = useBlockNote({
  // Tells BlockNote which blocks to use.
  blockSchema: {
    // Adds all default blocks.
    ...defaultBlockSchema,
    // Adds the custom image block.
    image: ImageBlock,
  }
})

Notice three details about this code snippet. First, since we still want the editor to use the Built-In Block Types, we add defaultBlockSchema to our custom block schema. Second, the key which we use for the custom image block is the same string we use for its type. Make sure that this is always the case for your own custom blocks. Finally, we provide the type of our schema as a type argument to BlockNoteEditor.

And we're done! You now know how to create custom blocks and add them to the editor. Head to Manipulating Blocks to see what you can do with them in the editor.

Limitations

While custom blocks open a lot of doors for what you can do with BlockNote, we're still working on improving the API and there are a few limitations for the kinds of blocks you can create.

Multiple Rich-Text Fields

Some block types may require having multiple editable rich-text fields in a single block. Tables, for example, have an editable field for each cell. However, since you can only include a single InlineContent component in your custom block, only one editable field per block is officially supported.

Depending on your use case, it may be possible to work around this issue by using editable fields that aren't read by BlockNote. However, there are some caveats to this:

  1. Keyboard navigation will skip these editable fields.
  2. The editor will lose focus if the cursor is in one of these editable fields.

Using the contenteditable Attribute

BlockNote relies on the HTML contenteditable attribute to determine where the keyboard cursor can move. Therefore, any elements you use inside render should have their contenteditable set to false.