We’re currently working on moving pepsized.com to JAMstack. This website has run and still does as a “classic” WordPress. We may still change our minds about the technology, but right now we are considering a static website generated by GatsbyJS with WordPress as a headless CMS.

There are a few challenges, in particular, our demos and custom meta fields, like those managing our freebies. There are also some content-related issues. For example, our CodePen embeds are no longer working on Gatsby ๐Ÿ˜ฑ

In this article, we’ll see what actually happens to our pens and how we can deal with that.

The problem

Let’s abstract from WordPress and Gatsby. We have our post content as a string and need to display it within a React component.

On PEPSized, we’ve always used the HTML (recommended) method of embedding pens so the content string contains this kind of markup:


const content = `<p class="codepen" data-user="pehaa" data-slug-hash="zbvbwd">
<!-- pen details --></p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>`

And we may try to do something link that:


import React from 'react'

const PostContent = ({ content }) => {
  return (
    <div dangerouslySetInnerHTML={{ __html: content }} />
  )
}

or, using the html-react-parser:


import React from 'react'
import HTMLReactParser from 'html-react-parser'

const PostContent = ({ content }) => {
  return (
    <div>{HTMLReactParser(content)}</div>
  )
}

See the Pen Embed pen with React and dangerouslySetInnerHTML by Paulina Hetman (@pehaa) on CodePen.

As you can see in the pen above, none of those methods work. If you use browser tools to check the HTML outcome, you can see that the <script> tag is rendered. The problem is that our script is not evaluated.

The solution

We will use html-react-parser. It parses an HTML string and converts it into React elements. Its optional callback replace(domNode) gives us the possibility to modify, replace and remove elements. In this case, we will “scan” our HTML for all CodePen-embed script nodes. We will remove all of them and instead we will create one and append it to the document head.

See the Pen Embed pen with React – html react parser by Paulina Hetman (@pehaa) on CodePen.

That’s how we implement it for Gatsby


import React from 'react'
import HTMLReactParser from 'html-react-parser'

const PostContent = ({ content }) => {
  /* check if it happens in the browser or on the server  */
  const isSSR = typeof document === 'undefined'
  /* we need to append the CodePen script only once  */
  let codePenScriptIsAppended = false
  const options = {
    replace: (node) => {
      if (
        node.name === 'script' &&
        node.attribs &&
        node.attribs.src === 'https://static.codepen.io/assets/embed/ei.js'
      ) {
        if (isSSR) {
          return
        }
        if (!codePenScriptIsAppended) {
          const script = document.createElement('script')
          script.src = node.attribs.src
          script.setAttribute('async', "")
          document.head.appendChild(script)
          codePenScriptIsAppended = true
        }
        return <React.Fragment />
      }
    }
  }
  return (
    <div>{HTMLReactParser(content, options)}</div>
  )
}

By the way, we use html-react-parser for a bunch of different things as well (and find it very cool! ๐Ÿ˜).

I'm a front-end developer, WordPress developer and trainer. Otherwise coding, cooking and doing yoga. Polish, married to a french guy Joe Vains with whom we live in the very center of Paris.
Follow @PeHaa on twitter and on CodePen.