Skip to main content

Navigation

  • Client impact
  • Writing

AI Solutions

  • AI Systems
  • AI Development

Software teams

  • Design Systems
  • Product Design & Engineering
  • API Platforms
  • View all services for software teams
Get in touch
  • AI Systems

    Model-agnostic AI systems and agents that do real work

    AI Development

    Custom apps and tools built with AI-enabled engineering

  • Design Systems

    Depth of experience that few can match

    Product Design & Engineering

    Experts in cross-functional collaboration

    API Platforms

    Node.js, React, & GraphQL at scale


    View all services for software teams
  • Client impact
  • Writing
  • Contact

Writing · Dec 13th, 2019 · 2 min read

Mauro Alvarez avatarMauro Alvarez avatar
Mauro Alvarez

How to safely inject HTML in React using an iframe

If you need to inject HTML into your React app and you don’t want to use `dangerouslySetInnerHTML`, this article is for you.

Services discussed

  • Front-end Engineering

Technology discussed

  • React
Poster: React logo on left. Plus symbol in center. Icon symbolising secure browsing on right.Poster: React logo on left. Plus symbol in center. Icon symbolising secure browsing on right.

Why (in most cases) you shouldn’t use dangerouslySetInnerHTML

As the react documentation says, 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.

In fewer words, dangerouslySetInnerHTML isn’t safe.

Why?

let’s say that you have a database with a bunch of article in HTML format that you want to display in your React app. Using dangerouslySetInnerHTML that would be quite easy to achieve:

function MyArticle({ articleId }) {
  return <div dangerouslySetInnerHTML={getArticleFromDB(articleId)} />
}

The problem with this is that the HTML you are injecting to your app could be malformed, it could have CSS/JS that breaks your app, or even worse, JS that steals data from your app.

How to make an iframe secure?

In order to make the iframe really safe, you need to add extra restrictions to the content inside of it. To do that, you should use the sandbox attribute.

<iframe id={IFRAME_ID} name={IFRAME_ID} sandbox="allow-same-origin" />

You should avoid using both allow-scripts and allow-same-origin, as that lets the embedded document remove the sandbox attribute — making it no more secure than not using the sandbox attribute at all.

How to inject and update the content in an iframe?

Here you have two options:

  • by using the iframe attribute srcdoc (which is not supported by IE and Edge)
  • by using the iframe.document.open()/write()/close()

Using srcdoc

the srcdoc property allows you to specify the content of the iframe, so using it is quite simple:

<iframe
  id={IFRAME_ID}
  name={IFRAME_ID}
  sandbox="allow-same-origin"
  srcDoc={iframeContent}
/>

Unfortunately srcdoc isn’t supported in IE and Edge. There is a polyfill but it isn’t useful in this case because it requires allow-scripts (and remember that’s not safe)

Using iframe.document.open()/write()/close()

This method is not straightforward as using srcdoc, but it works the good thing is that works in all browsers.

const IFRAME_ID = 'my-iframe'
const IFRAME_CONTAINER_ID = 'my-iframe-container'

export const ArticleBody = (props: Props) => {
  useEffect(() => {
    const setIframeContent = (body) => {
      const currentIframe = document.getElementById(IFRAME_ID)
      const iframeContainer = document.getElementById(IFRAME_CONTAINER_ID)
      if (iframeContainer) {
        const newIframe = frames[IFRAME_ID]
        if (newIframe !== null) {
          const iframeDocument = newIframe.document
          iframeDocument.open()
          iframeDocument.write(`${body}`)
          iframeDocument.close()
        }
      }
    }

    setIframeContent(props.body)
  }, [props.body])
}

Conclusion

I hope you’ve found this article useful! Start a conversation with the author in Twitter on what you think about this article.

Services discussed

  • Front-end Engineering

Technology discussed

  • React
Mauro Alvarez avatarMauro Alvarez avatar
Mauro Alvarez

Software developer with a focus on quality, speed, and clean user experience.

Related content

  • From Vibes to Durable Context

    article

    August 2026·4 min read
  • Why your design system is the most important input to Claude Code

    article

    March 2026·5 min read
  • Progressive Web Apps (PWAs): A stepping stone towards a native mobile application

    article

    August 2024·11 min read
  • Building a Multi Brand Design System with Tailwind: Tips, Tricks and Tradeoffs

    article

    June 2024·16 min read
  • Storybook and Mock APIs: A Powerful Prototyping Combo

    article

    May 2024·12 min read
  • Track: The Best Layout Component That You’ve Probably Never Heard Of

    article

    June 2023·
    (opens in new tab)

Have an idea to explore?

Get in touch

Footer

Thinkmill is a member of the Tech Council of Australia(opens in new tab).

AI Solutions

  • AI Systems
  • AI Development

Software teams

  • Design Systems
  • Product Design & Engineering
  • API Platforms
  • View all software teams

Client impact

  • ELMO
  • Tiimely
  • Atlassian
  • Reckon
  • AnywhereWorks
  • View all client impact

Open Source

  • Keystone (opens in new tab)
  • Keystatic (opens in new tab)
  • React Select (opens in new tab)
  • Classnames (opens in new tab)
  • Manypkg (opens in new tab)
  • Changesets (opens in new tab)