What Is DangerouslySetInnerHTML?

What Is DangerouslySetInnerHTML?

And is it really so dangerous?

Image for postPhoto by WOCinTech Chat on Flickr

In this article, we will be discussing what dangerouslySetInnerHTML is, how it is used, what the differences are between dangerouslySetInnerHTML and innerHTML, and a real project where it proves to be useful.

What?

dangerouslySetInnerHTML is an attribute under DOM elements in React.

According to the official documentation, dangerouslySetInnerHTML is React?s replacement for using innerHTML in the browser DOM.

This means that if in React if you have to set HTML programmatically or from an external source, you would have to use dangerouslySetInnerHTML instead of traditional innerHTML in Javascript.

In simple words, using dangerouslySetInnerHTML, you can set HTML directly from React.

How?

First, let?s take a look at how innerHTML works.(https://codepen.io/lelouchb/pen/MWaMYde)

innerHTML

Here is the Javascript code:

let root = document.querySelector(‘#root’)root.innerHTML = `<h2>This text is set using innerHTML</h2>`

Using innerHTML is simple. You just have to use it using dot notation with the DOM element and pass the HTML string using quotes or template literals.

Now let?s see how the same is achieved using dangerouslySetInnerHTML.(https://codepen.io/lelouchb/pen/PoPrqEw)

dangerouslySetInnerHTML

Code:

function App(){return(<div dangerouslySetInnerHTML={{ __html: `This text is set using dangerouslySetInnerHTML` }}> </div>) }ReactDOM.render(<App />, document.querySelector(“#root”));

While using dangerouslySetInnerHTML, you will have to pass an object with a __html key. (Note that the key consists of two underscores). The object dangerouslySetInnerHTML can be passed via different methods.

As a variable:

function App(){ const markup={ __html: ‘This text is set using dangerouslySetInnerHTML’}return(<div dangerouslySetInnerHTML={markup}> </div>) }ReactDOM.render(<App />, document.querySelector(“#root”));

As a function:

function App(){ const markup=()=>{return{ __html: ‘This text is set using dangerouslySetInnerHTML’}}return(<div dangerouslySetInnerHTML={markup()}> </div>) }ReactDOM.render(<App />, document.querySelector(“#root”));

Difference

The immediate effect of using innerHTML versus dangerouslySetInnerHTML is identical: The DOM node will update with the injected HTML. However, behind the scenes, when you use it, it lets React know that the HTML inside of that component is not something it cares about.

Because React uses a virtual DOM, when it goes to compare the difference against the actual DOM, it can straight-up bypass checking the children of that node because it knows the HTML is coming from another source. So there are performance gains.

More importantly, if you simply use innerHTML, React has no way to know the DOM node has been modified. The next time the render function is called, React will overwrite the content that was manually injected with what it thinks the correct state of that DOM node should be.

Why Dangerous?

Improper use of the innerHTML can open you up to a cross-site scripting (XSS) attack. The prop name dangerouslySetInnerHTML is intentionally chosen to be frightening, and the prop value (an object instead of a string) can be used to indicate sanitized data. You need to make sure your HTML is structured properly and sanitized before inserting it into your page. You can use libraries like dompurify to do so.

When?

The prop name was intentionally chosen to be frightening so when it should be used? Let?s discuss a real-life React project where a developer will have to use dangerouslySetInnerHTML.

HackerNewsAPI

Projects made using HackerNews API are very common, simple to make, and fun, but most of the API requests made in them are for the id?s of the items of topstories, beststories, etc. Here is the response JSON data of one of the items of topstories:

https://hacker-news.firebaseio.com/v0/item/23331287.json?print=pretty

{ “by” : “lostmsu”, “descendants” : 251, “id” : 23331287, “kids” : [ 23332582, 23333565, 23332777, 23334075, 23331976, 23332122, 23332664, 23332047, 23333745, 23332119, 23332909, 23332118, 23332674, 23333572, 23334374, 23331882, 23334410, 23331780, 23332176, 23331823, 23332297, 23333192, 23333690, 23334269, 23332755, 23333735, 23333025, 23331297, 23333672, 23332123, 23332298, 23332913, 23333112, 23334176, 23333814, 23333849, 23334245, 23333261, 23332823, 23332079, 23331890, 23332360, 23332197, 23332840 ], “score” : 844, “time” : 1590620950, “title” : “The Day AppGet Died”, “type” : “story”, “url” : “https://keivan.io/the-day-appget-died/”}

But the request made to items in askstories returns something interesting. Let?s take a look at it.

https://hacker-news.firebaseio.com/v0/item/23325385.json?print=pretty

{ “by” : “behnamoh”, “descendants” : 3, “id” : 23325385, “kids” : [ 23326663, 23326382, 23325618 ], “score” : 1, “text” : “As a heavy user, I basically <i>live</i> in my browser. However, extensions do slow down the browser, which makes me think there's gotta be a better way. I believe it's high time we had an operating system which is fully optimized as a browser. Extensions then, would be apps on the OS, and probably won't slow it down. Have you seen any OS that is browser-first?”, “time” : 1590595712, “title” : “Ask HN: Can operating systems be browsers?”, “type” : “story”}

As you can see, the textfield contains HTML tags <i>live</i>, and you can?t simply show them in the HTML as compared to other fields containing string, numbers, etc. This is just one example. There are response data that contains numbers of HTML tags.

Here is the actual use case of dangerouslySetInnerHTML, and responses such as discussed above are rendered in the HTML using dangerouslySetInnerHTML.

Thanks for reading!

16