abinas patra
abinas patra

Reputation: 389

Render JSX element in react-contenteditable

In react-contenteditable, the html attributes only accepts string, how can I manage to add JSX element with eventlistener with in the string.

Sandbox

import ContentEditable from "react-contenteditable";
import "./styles.css";

const text = "I want to order cheese chicken pizza.";

const Elems = {
  cheese: (
    <span style={{ color: "red" }} onClick={() => alert("clicked cheese span")}>
      cheese
    </span>
  ),
  chicken: (
    <span
      style={{ color: "red" }}
      onClick={() => alert("clicked chicken span")}
    >
      chicken
    </span>
  )
};

export default function App() {
  const swapText = () => {
    const text_array = text.split(" ");
    console.log(text_array);
    const a = text_array.map((item) => {
      if (item in Elems) item = Elems[item];
      else item += " ";
      return item;
    });
    return a;
  };

  return (
    <div className="App">
      <h2>React contenteditable</h2>
      <ContentEditable html={swapText()} />
    </div>
  );
}

Upvotes: 0

Views: 474

Answers (1)

Ori Drori
Ori Drori

Reputation: 191976

You can convert react elements to markup using ReactDOMServer.renderToStaticMarkup(element). This would help with the styles, but not with the click handler:

if (item in Elems) item = renderToStaticMarkup(Elems[item]);

For the items to be clickable, you'll need to pass an onClick handler to <ContentEditable> component (or a parent of it):

<ContentEditable onClick={handleClick} html={swapText()} />

You would also need to identify the clickable elements. In this example, I've data-action tags to both of them:

const Elems = {
  cheese: (
    <span style={{ color: 'red' }} data-action="cheese">
      cheese
    </span>
  ),
  chicken: (
    <span style={{ color: 'red' }} data-action="chicken">
      chicken
    </span>
  )
};

The click handler searches the event target or a parent that has the data-action tag using Element.closest(), if it finds one it acts on the tags value:

const handleClick = (e) => {
  const target = e.target.closest('[data-action]');

  if (!target) return;

  const action = target.dataset.action;

  alert(action);
};

Working example - sandbox

Upvotes: 1

Related Questions