Search code examples
javascriptreactjsdraftjs

how to add caption to images in draft js?


Is is possible to render an input (for adding caption to images) inside the draft js and can get the data which is typed by user? I am familiar with "custom block rendering" concept and followed the instruction which is provided by https://draftjs.org/docs/advanced-topics-custom-block-render-map/ But, when I wanted to write something in the input, I faced the below error:

invariant.js:40 Uncaught Invariant Violation: Unknown DraftEntity key: null.

In fact, block?.getEntityAt(0) returns null, since character list changes when I started to type.

This is the custom block renderer code:

import React from "react";
import { fromJS } from "immutable";

export const CustomBlockRenderer = (block, editorState, props) => {
  if (block.getType() === "atomic") {
    return {
      component: Media,
      editable: false,
    };
  }
  return null;
};

const Image = (props) => {
  if (!!props.src) {
    return <img src={props.src} />;
  }
  return null;
};

const Media = (props) => {
  const entity = props.contentState?.getEntity(props?.block?.getEntityAt(0));
  const { src } = entity?.getData();

  const type = entity?.getType();

  let customBlock;

  if (type === "image") {
    customBlock = (
      <figure className="custom-block__image-wrap">
        <Image src={src?.url} className="custom-block__image" />
        <figcaption className="custom-block__caption">{src?.caption}</figcaption>
      </figure>
    );
  } else {
    return null;
  }

  return customBlock;
};


Solution

  • I faced with a similar issue recently. Here the simplified demo of how it can work. Pay attention that EditorBlock component from draft-js is used on the image caption node. You should use EditorBlock in your custom component if you want an editable area inside the custom component.

    class MyCustomBlock extends React.Component {
      render() {
        const imgSrc = this.props.block.get("data").src;
    
        return (
          <div className="my-custom-block">
            <figure className="custom-block__image-wrap">
              <img src={imgSrc} className="custom-block__image" />
              <figcaption className="custom-block__caption">
                <EditorBlock {...this.props} />
              </figcaption>
            </figure>
          </div>
        );
      }
    }
    

    enter image description here