Dynamically Create a Script Element with JavaScript

Abstract image used to represent Dynamically Create a Script Element with JavaScript
Image by Blake Connally.

There are many reasons why you might want to dynamically inject a <script> tag into your document from the client side. Here, I very briefly discuss how we can use the document.createElement() method, creating a new element and then setting its src attribute to the URL of the script we want to load. Finally, we can append the newlygenerated element to the HTML page via either document.head or document.body.

For example, let's say we want to load the script example.js and add it to the head of the HTML page. The code would look something like this:

var script = document.createElement('script');
script.src = 'example.js';
script.onload = function () {
  console.log('example.js is ready');
};
script.onerror = function () {
  console.error('Could not load example.js');
};
document.head.appendChild(script);

The resulting markup would look like this:

<script src="example.js"></script>

The destination needs to exist before you append the element: document.head is usually available early, whilst document.body may not exist yet. You don't need to wait for every page asset to load. An external script inserted this way loads asynchronously, so put work that depends on it in its load handler and handle error too.

You can also set innerHTML of the script element, rather than using an external file via src. This allows you to dynamically inject rudimentary JavaScript code into the head of your page.

var script = document.createElement('script');
script.innerHTML = "console.log('example')";
document.head.appendChild(script);

//=> 'example'

This creates an inline <script> in the document head. It runs when inserted, provided the page's script policy allows it. Only use code you control here.

<script>
  console.log('example');
</script>

..and that is as simple as it gets!

Postscript

June 2026: This shows the mechanics of injecting a <script> element, but thirdparty scripts deserve more scrutiny than this short note gives them. Consent, security, loading order and Core Web Vitals usually matter more than the DOM API itself.

Have a complex web platform issue?

Tell me what is blocked, what has changed, and what needs to be true after the fix. I'll come back with a practical next step.