Block Level Marks: Links on Images

I’m trying to implement links on images by using the tr.setNodeMarkup api, which seems allowed given that marks is a possible last parameter to that method.

I’ve also modified the image spec such that it allows for link marks:

const imageSpec = {
  attrs: {
    src: { default: null },
    alt: { default: null },
    title: { default: null }
  inline: false,
  group: "block",
  marks: "link",
  draggable: true,
  parseDOM: [
      tag: "img[src]",
      getAttrs(img) {
        return { src: img.src, alt: img.alt, title: img.title };
  toDOM(node) {
    return ["img", { ...node.attrs }];

And the snippet that applies the mark is

        if (selection instanceof NodeSelection) {
          const { node, from } = selection;
          if (node.type === schema.nodes.image) {
            console.log("before", node.marks);
            tr.setNodeMarkup(from, null, node.attrs, [
    { href })
            console.log("after", tr.doc.resolve(from).nodeAfter.marks);

The issue I’m running into is that the mark seems to be correctly applied when I set breakpoints within setNodeMarkup but checking the doc both by logging it after the setNodeMarkup and after the transaction is dispatch, the block level link doesn’t seem to get applied.

Reproducible sandbox: snowy-butterfly-cmwpw - CodeSandbox

The problem there appears to be that your schema doesn’t allow link marks in the image’s parent node.

Oh, is that how block level marks works: if you want to wrap a block in a mark, you have to allow marks in the parent of the block. In hindsight, that makes sense given its what one does for inline marks. Thanks!