2

How to convert JSON to normal html with html elements in a react app?

Note that dangerouslySetInnerHTML can be dangerous if you do not know what is in the HTML string you are injecting

According to react docs -

dangerouslySetInnerHTML is React’s replacement for using innerHTML in the browser DOM. In general, setting HTML from code is risky because it’s easy to inadvertently expose your users to a cross-site scripting (XSS) attack. So, you can set HTML directly from React, but you have to type out dangerouslySetInnerHTML and pass an object with a __html key, to remind yourself that it’s dangerous.

I have created a code sandbox below: https://codesandbox.io/s/relaxed-sunset-tlmr2?file=/src/App.js

The output just renders as string instead of html elements.

Here is my code:

import React from "react";
import "./styles.css";

const blocks = {
  time: 1602725895949,
  blocks: [
    {
      type: "header",
      data: {
        text: "This is a heading",
        level: 2
      }
    },
    {
      type: "paragraph",
      data: {
        text: "This is a paragraph"
      }
    }
  ]
};

export default function App() {
  function convertToHtml({ blocks }) {
    console.log(blocks);
    var convertedHtml = "";
    blocks.map((block) => {
      switch (block.type) {
        case "header":
          convertedHtml += `<h${block.data.level}>${block.data.text}</h${block.data.level}>`;
          break;
        case "paragraph":
          convertedHtml += `<p>${block.data.text}</p>`;
          break;
        default:
          console.log("Unknown block type", block.type);
          break;
      }
    });

    return <React.Fragment>{convertedHtml}</React.Fragment>;
  }

  return (
    <div className="App">
      <h1>JSON to html below</h1>
      {convertToHtml(blocks)}
    </div>
  );
}
3
  • Does this answer your question? Insert HTML with React Variable Statements (JSX) Commented Oct 15, 2020 at 2:59
  • 1
    You have to return the JSX directly instead of making it a string. I'll post an answer in a few minutes. Commented Oct 15, 2020 at 3:00
  • @diedu I edited the question to show that dangerouslySetInnerHTML is not recommended according to react docs. The answer you posted uses dangerouslySetInnerHTML Commented Oct 15, 2020 at 3:05

3 Answers 3

4

When you are generating HTML in React you don't want to treat it as a string, you want to treat it as components. Instead of returning a literal string '<p>${block.data.text}</p>' you can return <p>{block.data.text}</p> which is valid JSX.

I've converted your switch statement into a function component which renders a single block. Note that null is the standard return for a component which doesn't render anything. For the case where you are making h1, h2, etc. dynamically, I saved that string as a capital letter variable so that React interprets it as a custom component instead of a built-in element.

export function Block({ type, data }) {
  switch (type) {
    case "header":
      const Element = "h" + data.level;
      return <Element>{data.text}</Element>;
    case "paragraph":
      return <p>{data.text}</p>;
    default:
      console.log("Unknown block type", type);
      return null;
  }
}

Then you can loop through the array of blocks and pass each block off as props to the Block component. Whenever you return elements from a loop, react throws a warning if you don't set a key, so I am using the array index as the key.

export default function App() {
  return (
    <div className="App">
      <h1>JSON to html below</h1>
      {blocks.blocks.map((block, i) => (
        <Block key={i} {...block} />
      ))}
    </div>
  );
}

Code Sandbox Link

Sign up to request clarification or add additional context in comments.

Comments

3

I have another answer.

Try this one. Now without dangerously HTML stuff.

import parse from "html-react-parser";

return <React.Fragment>{parse(convertedHtml)}</React.Fragment>;

Package: https://codesandbox.io/examples/package/html-react-parser

The same Code Sandbox

https://codesandbox.io/s/modern-glitter-1nnkc?file=/src/App.js:27-65

2 Comments

I upvoted your answer but I really try to avoid installing more packages as much as possible. I am hoping there might be a jsx way of doing this.
You can instead of concatenating string use React.createElement('div', {}, 'text')
2

You have to use the property dangerouslySetInnerHTML.

Like this:

return <React.Fragment>{<div dangerouslySetInnerHTML={{ __html: convertedHtml }} />}</React.Fragment>;

I also forked your Code Sandbox with the solution: https://codesandbox.io/s/modern-glitter-1nnkc?file=/src/App.js:1542-1674

Mark as answer if it works. Thanks

1 Comment

According to react docs, this is not a good practice - easy to inadvertently expose your users to a cross-site scripting (XSS) attack, you can set HTML directly from React, but you have to type out dangerouslySetInnerHTML and pass an object with a __html key, to remind yourself that it’s dangerous.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.