Skip to content

Custom inline content not updating in the document #2142

Closed

Description

@SiTaggart

Describe the bug
When inserting a simple custom inline content, updating the text in the editor is visible, but if you try to reteive the document from the editor the custom inline content is empty.

To Reproduce
Use the slash command to insert a tag, click the red tag, type some letters. Hit the export button, you'll see the JSON update and the content of the custom_tag type of content is alway empty

{
    "id": "9e1fc163-eb41-4e6a-9d27-08985f84d248",
    "type": "paragraph",
    "props": {
      "backgroundColor": "default",
      "textColor": "default",
      "textAlignment": "left"
    },
    "content": [
      {
        "type": "text",
        "text": "fsffs ",
        "styles": {}
      },
      {
        "type": "custom_tag",
        "props": {},
        "content": []
      }
    ],
    "children": []
  },

stackblitz link

Question

What am I doing wrong? The docs around editable custom inline content is really thin. Took a while to work out I needed a ref pointing to the content ref on an element for the content to be shown ref={props.contentRef}. But cannot for the life of me figure out how to make these editable and exportable

It's curious that if you edit an initialContent tag it will update the document with the content, but if you insert a new one, it won't grab the content from the new inline content.

Misc

  • Node version:
  • Package manager:
  • Browser:
  • I'm a sponsor and would appreciate if you could look into this sooner than later 💖

Activity

  1. YousefED commented on Oct 31, 2025

    @YousefED
    Collaborator

    Hi Simon,

    Thanks for the feedback (we'll have a fresh look at the docs) and stackblitz. For me, it works straight out-of-the-box when I try the stackblitz;

    Image

    Are you sure you're still having the issue?

  2. SiTaggart commented on Oct 31, 2025

    @SiTaggart
    Author

    Yeah, like I mentioned in the issue:

    It's curious that if you edit an initialContent tag it will update the document with the content, but if you insert a new one, it won't grab the content from the new inline content.

    So try inserting a new tag from the slash menu (it's right at the bottom), and then edit the content and try export. You'll see the content array remain empty even if it has content displayed in the editor

    Image
  3. edwardbrowncross commented on Nov 6, 2025

    @edwardbrowncross

    Just to add a few more observations:

    1. If you instantiate the custom inline content from the slash menu with child content, like this:
    onItemClick: () =>
      editor.insertInlineContent([
        {
          type: 'custom_tag',
    +     content: [
    +       {
    +         type: 'text',
    +         text: 'content from slash menu',
    +         styles: {},
    +       },
    +     ],
        },
      ]),

    Then:

    • That child content is not rendered into the ref'd component (though it is being passed correctly to the inlineContent prop)
    • That content is always exported exactly as instantiated, regardless of any text entered into the ref'd component
    Image

    So it really looks like the component you give to the ref isn't being wired up to the internal state in either direction.

    1. Custom inline content inserted with editor.replaceBlocks has the same behaviour, so it is not just slash menu or insertInlineContent
  4. nperez0111 commented on Nov 6, 2025

    @nperez0111
    Contributor

    Do you guys happen to be using the ProseMirror devtools by any chance?

    ~~I've found that when the devtools are disabled, it works & when they are enabled, it breaks like it does for you both @SiTaggart & @edwardbrowncross ~~

    ~~I think this may just be related to: TeemuKoivisto/prosemirror-dev-toolkit#84 ~~

    Oh actually maybe not, it works for existing inline content, but not for newly created ones.

  5. nperez0111 commented on Nov 6, 2025

    @nperez0111
    Contributor

    OK, after much debugging, I've figured out that this is mostly a CSS issue. There is some work that we can do to make this experience better. It seems that we do not have any examples of editable inline content, which would explain why we did not catch this earlier.

    I'm can't justify spending more time on this right now. So, I'm leaving my diff here so that I or @matthewlipski can get back to this later:

    diff --git i/examples/01-basic/01-minimal/src/App.tsx w/examples/01-basic/01-minimal/src/App.tsx
    index a3b92bafd..5d1ece62c 100644
    --- i/examples/01-basic/01-minimal/src/App.tsx
    +++ w/examples/01-basic/01-minimal/src/App.tsx
    @@ -1,12 +1,114 @@
    +import {
    +  BlockNoteEditor,
    +  BlockNoteSchema,
    +  defaultInlineContentSpecs,
    +  filterSuggestionItems,
    +  insertOrUpdateBlock,
    +} from "@blocknote/core";
     import "@blocknote/core/fonts/inter.css";
     import { BlockNoteView } from "@blocknote/mantine";
     import "@blocknote/mantine/style.css";
    -import { useCreateBlockNote } from "@blocknote/react";
    +import {
    +  createReactInlineContentSpec,
    +  DefaultReactSuggestionItem,
    +  getDefaultReactSlashMenuItems,
    +  SuggestionMenuController,
    +  useCreateBlockNote,
    +  useEditorChange,
    +} from "@blocknote/react";
    +import { useCallback, useState } from "react";
    +
    +const styles = {};
    +const CustomTag = createReactInlineContentSpec(
    +  {
    +    type: "custom_tag",
    +    propSchema: {},
    +    content: "styled",
    +  },
    +  {
    +    render: (props) => {
    +      return (
    +        <div className={"inline-content"}>
    +          <span style={styles} ref={props.contentRef}></span>
    +        </div>
    +      );
    +    },
    +  },
    +);
    +const schema = BlockNoteSchema.create().extend({
    +  inlineContentSpecs: {
    +    custom_tag: CustomTag,
    +  },
    +});
    +
    +const insertCustomTagItem = (
    +  editor: typeof schema.BlockNoteEditor,
    +): DefaultReactSuggestionItem => ({
    +  title: "Insert custom Tag",
    +  badge: "tag",
    +  size: "small",
    +  onItemClick: () =>
    +    editor.insertInlineContent([
    +      {
    +        type: "custom_tag",
    +      },
    +    ]),
    +  aliases: ["tag", "t"],
    +  group: "Other",
    +  icon: <div>hi</div>,
    +  subtext: "Insert a custom tag to the note",
    +});
    +
    +// List containing all default Slash Menu Items, as well as our custom one.
    +const getCustomSlashMenuItems = (
    +  editor: typeof schema.BlockNoteEditor,
    +): DefaultReactSuggestionItem[] => [
    +  ...getDefaultReactSlashMenuItems(editor),
    +  insertCustomTagItem(editor),
    +];
     
     export default function App() {
    +  console.log("render");
    +  const [docJSON, setDocJSON] = useState({});
       // Creates a new editor instance.
    -  const editor = useCreateBlockNote();
    +  const editor = useCreateBlockNote({
    +    schema,
    +    initialContent: [
    +      {
    +        type: "paragraph",
    +        content: [
    +          {
    +            type: "text",
    +            text: "Welcome to this demo! ",
    +            styles: {},
    +          },
    +          // {
    +          //   type: "custom_tag",
    +          //   props: {},
    +          //   content: "ddfsdfsd",
    +          // },
    +        ],
    +      },
    +    ],
    +  });
     
    -  // Renders the editor instance using a React component.
    -  return <BlockNoteView editor={editor} />;
    +  useEditorChange(() => {
    +    setDocJSON(editor.prosemirrorState.doc.toJSON());
    +  }, editor);
    +
    +  // Renders the editor instance.
    +  return (
    +    <>
    +      <BlockNoteView editor={editor} slashMenu={false}>
    +        <SuggestionMenuController
    +          triggerCharacter={"/"}
    +          // Replaces the default Slash Menu items with our custom ones.
    +          getItems={async (query) =>
    +            filterSuggestionItems(getCustomSlashMenuItems(editor), query)
    +          }
    +        />
    +      </BlockNoteView>
    +      <pre>{JSON.stringify(docJSON, null, 2)}</pre>
    +    </>
    +  );
     }
    diff --git i/packages/react/src/schema/ReactInlineContentSpec.tsx w/packages/react/src/schema/ReactInlineContentSpec.tsx
    index 341c8981e..3ee2dd566 100644
    --- i/packages/react/src/schema/ReactInlineContentSpec.tsx
    +++ w/packages/react/src/schema/ReactInlineContentSpec.tsx
    @@ -11,6 +11,7 @@ import {
       InlineContentSchemaWithInlineContent,
       InlineContentSpec,
       inlineContentToNodes,
    +  mergeCSSClasses,
       nodeToCustomInlineContent,
       PartialCustomInlineContentFromConfig,
       Props,
    @@ -190,6 +191,11 @@ export function createReactInlineContentSpec<
                       contentRef={(element) => {
                         ref(element);
                         if (element) {
    +                      element.className = mergeCSSClasses(
    +                        "bn-inline-content",
    +                        element.className,
    +                      );
    +                      element.dataset.nodeViewContent = "";
                           element.dataset.editable = "";
                         }
                       }}
    @@ -224,7 +230,7 @@ export function createReactInlineContentSpec<
               {
                 className: "bn-ic-react-node-view-renderer",
                 as: "span",
    -            // contentDOMElementTag: "span", (requires tt upgrade)
    +            contentDOMElementTag: "span",
               },
             )(props);
         },
    diff --git i/playground/src/style.css w/playground/src/style.css
    index ff271345e..26bd68ffa 100644
    --- i/playground/src/style.css
    +++ w/playground/src/style.css
    @@ -66,3 +66,11 @@ body {
         padding: 0 !important;
       }
     }
    +
    +[data-inline-content-type="custom_tag"] [data-editable] {
    +  display: inline-block;
    +  color: white;
    +  min-height: 20px;
    +  min-width: 50px;
    +  background: red;
    +}
    
  6. clyce commented on Dec 19, 2025

    @clyce

    Hello, I am facing exactly the same issue, where customInlineContent not showing when passed as initialContent, before any version update is done to the blockNote, could you kindly provide a temp fix solution on the app level for this? Thanks a lot :)

  7. nperez0111 commented on Dec 19, 2025

    @nperez0111
    Contributor

    Sorry @clyce we have other things that we are working towards at the moment, so we don't have the capacity to look into this further (at least) until after the end of the year.

    If you would like to look into this, feel free to do so, I'm happy to answer any questions you have. It'd be great to have this resolved & have a PR that we can help fix this for others!

  8. added
    needs-triageIssue has not yet been reviewed or classified by maintainers.
    on Feb 3, 2026
  9. added
    bug:P2High: Core functionality significantly impacted.
    and removed
    needs-triageIssue has not yet been reviewed or classified by maintainers.
    on Feb 23, 2026
  10. nperez0111 commented on Oct 24, 2026

    @nperez0111
    Contributor

    #3251 should have fixed this issue

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bug:P2High: Core functionality significantly impacted.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions