Docs
Cursor & Selections

Cursor & Selections

TODO: refactor to use hooks? TODO: are these examples really useful / can we come up with something better?

If you want to know which block(s) the user is currently editing, you can do so using cursor positions and selections.

Text Cursor

The text cursor is the blinking vertical line you see when typing in the editor. BlockNote uses TextCursorPosition objects to give you information about the block it's in as well as those around it:

type TextCursorPosition = {
  block: Block;
  prevBlock: Block | undefined;
  nextBlock: Block | undefined;
};

block: The block currently containing the text cursor. If the cursor is in a nested block, this is the block at the deepest possible nesting level.

prevBlock: The previous block at the same nesting level. Undefined if the block containing the text cursor is the first child of its parent, or the first block in the editor.

nextBlock: The next block at the same nesting level. Undefined if the block containing the text cursor is the last child of its parent, or the last block in the editor.

Getting Text Cursor Position

You can get a snapshot of the current text cursor position using the following call:

getTextCursorPosition(): TextCursorPosition;
 
// Usage
const textCursorPosition = editor.getTextCursorPosition();

returns: A snapshot of the current text cursor position.

Setting Text Cursor Position

You can set the text cursor position to the start or end of an existing block using the following call:

setTextCursorPosition(
  targetBlock: BlockIdentifier,
  placement: "start" | "end" = "start"
): void;
 
// Usage
editor.setTextCursorPosition(targetBlock, placement);

targetBlock: The identifier of an existing block that the text cursor should be moved to.

placement: Whether the text cursor should be placed at the start or end of the block.

Throws an error if the target block could not be found.

Demo: Highlighting Block Containing the Text Cursor

If you need a visualization for which block contains the text cursor, the demo below highlights it in blue in real time.

import { BlockNoteView, useCreateBlockNote } from "@blocknote/react";
import "@blocknote/react/style.css";
 
import "@blocknote/react/style.css";
import { useCallback } from "react";
 
export default function App() {
  // Creates a new editor instance.
  const editor = useCreateBlockNote();
 
  const onSelectionChange = useCallback(() => {
    // Gets the block currently hovered by the text cursor.
    const hoveredBlock = editor.getTextCursorPosition().block;
 
    // Traverses all blocks.
    editor.forEachBlock((block) => {
      if (
        block.id === hoveredBlock.id &&
        block.props.backgroundColor !== "blue"
      ) {
        // If the block is currently hovered by the text cursor, makes its
        // background blue if it isn't already.
        editor.updateBlock(block, {
          props: { backgroundColor: "blue" },
        });
      } else if (
        block.id !== hoveredBlock.id &&
        block.props.backgroundColor === "blue"
      ) {
        // If the block is not currently hovered by the text cursor, resets
        // its background if it's blue.
        editor.updateBlock(block, {
          props: { backgroundColor: "default" },
        });
      }
 
      return true;
    });
  }, [editor]);
 
  // Renders the editor instance.
  return (
    <BlockNoteView editor={editor} onSelectionChange={onSelectionChange} />
  );
}
 

Selections

When you highlight content using the mouse or keyboard, this is called a selection. BlockNote uses Selection objects to show which blocks the current selection spans across:

type Selection = {
  blocks: Block[];
};

blocks: The blocks currently spanned by the selection, including nested blocks.

Getting Selection

You can get a snapshot of the current selection using the following call:

getSelection(): Selection | undefined;
 
// Usage
const selection = editor.getSelection();

returns: A snapshot of the current selection, or undefined if no selection is active.

Demo: Highlighting Blocks Spanned by Selection

If you need a visualization for which blocks the text cursor spans, the demo below highlights them in blue in real time.

import { BlockNoteView, useCreateBlockNote } from "@blocknote/react";
import "@blocknote/react/style.css";
import { useCallback } from "react";
 
export default function App() {
  // Creates a new editor instance.
  const editor = useCreateBlockNote();
 
  const onSelectionChange = useCallback(() => {
    // Gets the blocks currently spanned by the selection.
    const selectedBlocks = editor.getSelection()?.blocks;
    // Converts array of blocks to set of block IDs for more efficient comparison.
    const selectedBlockIds = new Set<string>(
      selectedBlocks?.map((block) => block.id) || []
    );
 
    // Traverses all blocks.
    editor.forEachBlock((block) => {
      // If no selection is active, resets the background color of each block.
      if (selectedBlockIds.size === 0) {
        editor.updateBlock(block, {
          props: { backgroundColor: "default" },
        });
 
        return true;
      }
 
      if (
        selectedBlockIds.has(block.id) &&
        block.props.backgroundColor !== "blue"
      ) {
        // If the block is currently spanned by the selection, makes its
        // background blue if it isn't already.
        editor.updateBlock(block, {
          props: { backgroundColor: "blue" },
        });
      } else if (
        !selectedBlockIds.has(block.id) &&
        block.props.backgroundColor === "blue"
      ) {
        // If the block is not currently spanned by the selection, resets
        // its background if it's blue.
        editor.updateBlock(block, {
          props: { backgroundColor: "default" },
        });
      }
 
      return true;
    });
  }, [editor]);
 
  // Renders the editor instance.
  return (
    <BlockNoteView editor={editor} onSelectionChange={onSelectionChange} />
  );
}