Adding and Executing Script Tags in React Render

Returning and rendering script tags in React components will definitely add them in the DOM but won’t really execute them. For example:

function Component(props) {
  return (
    <div>
      <h1>Hello React!</h1>
      <script src="htttps://cdnjs.cloudflare.com/ajax/libs/react/18.0.0/umd/react.production.min.js"></script>
      <script>window.alert('Hello React!');</script>
    </div>
  );
}

The first script tag won’t load the external script where as the second one won’t execute the inline script (alert). But they’ll definitely be rendered in the DOM, you can fire up the dev tools and inspect elements.

The reason why the execution doesn’t happen is because internally React uses innerHTML on the respective elements to actually set/inject/flush the changes into the DOM. The HTML5 spec specifies that user agents (browsers) must not execute the script tags set via innerHTML (more info at MDN).

So what do we do then ?

Create Scripts on Render and Add them to DOM with Vanilla JavaScript

When a component mounts (componentDidMount for Class components) or renders (useEffect in Functional component), we can create a script element, set its src or innerHTML and then append it to the HTML document’s head or body.

useEffect(() => {
  // componentDidMount() {}
  const externalScript = document.createElement('script');
  externalScript.src = '...';
  externalScript.async = true;
  document.head.append(externalScript);

  const inlineScript = document.createElement('script');
  inlineScript.innerHTML = '...';
  document.body.append(inlineScript);

  // componentWillUnmount() {}
  return () => {
    externalScript.remove();
    inlineScript.remove();
  };
}, []);

If you want you can throw the entire logic of generating the script element into a utility or helper function and then call that with minimal arguments.

Use a Third Party Library like Helmet that Does Exactly What We Did Above

react-helmet takes plain HTML tags and outputs the same in document.head (<head />).

// After `npm i react-helmet`
import { Helmet } from 'react-helmet';

function Component(props) {
  return (
    <div>
      <h1>Hello React!</h1>
      <Helmet>
        <script src="..."></script>
        <script>...</script>
      </Helmet>
    </div>
  );
}

Hope that helps!

Leave a Reply

Your email address will not be published.