A Detailed Breakdown of the <script> Tag

Share this article

When the <script> tag was originally introduced, it was used to add only the most basic level of interactivity to web pages. But the web has changed a lot, and the <script> tag has evolved. The proliferation of JavaScript has made it one of the most important HTML tags. This article explores the <script> tag in detail, including best practices for using it in modern web pages.

Specifying the Scripting Language

While JavaScript is the default scripting language of the web, browsers can support any number of additional languages. For example, Internet Explorer also supports a scripting language derived from Visual Basic named VBScript. In order to specify the scripting language of choice, the <script> tag’s “type” attribute is used. Technically, “type” specifies the MIME type of the script. The following example uses “type” to specify JavaScript’s MIME type, “text/javascript”.

<script type="text/javascript">
  // JavaScript code here
</script>

In older versions of HTML it was necessary to specify a value for “type”. However, starting in HTML5, “type” defaults to “text/javascript”. This decision was made because the W3C realized that JavaScript is the only universally supported scripting language. Therefore, HTML5 <script> tags can be shortened in the following fashion.

<script>
  // JavaScript code here
</script>

The “language” Attribute

There is a second attribute, “language”, which can be used to specify the scripting language. Unlike “type”, the possible values for “language” were never standardized. This attribute has been deprecated for a long time now, but some people still use it. It should not be used under any circumstances.

Inline and External Scripts

The <script> tag allows code to either be embedded directly into HTML, or included from external script files. Inline scripts are created by placing code between <script> and </script> tags in an HTML file. The following code shows an example inline <script>.

<script>
  // Inline JavaScript code here
</script>

Inline scripts are a quick and easy way to add code to web pages. However, large scripts can also lead to cluttered HTML files. The alternative approach is to include code in external script files. The external files are referenced via a URL specified by the “src” attribute. The following example shows how external script files are included. In this example, the external script file is named external.js, and is located in the same directory as the HTML file. Also, note that the closing </script> tag is still required.

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

XHTML Compatibility

XHTML rules are much stricter than those of HTML. When special XML characters (such as & and <) are used in scripts in XHTML files, they cause errors. The simplest workaround is to use external script files. However, if you simply must write inline scripts, then you will need to include CDATA (character data) sections in your file. Within CDATA sections the special XML characters can be used freely. The following example uses a CDATA section that is compatible with both XHTML and HTML syntax. Note that XHTML also requires the use of the “type” attribute.

<script type="text/javascript">
//<![CDATA[
  alert((1 < 2) && (3 > 2));
//]]>
</script>

Dynamic Script Tag Injection

Dynamic script tag injection is a technique in which new <script> elements are created at runtime. When the new <script> is added to the page, its “src” URL is automatically downloaded and executed. The following code shows an example dynamic script tag injection. In the example, a new <script> element is created using the document.createElement() function. Next, the “src” attribute is set to the URL of the script file. Finally, the new element is added to the document’s head, causing the script to be downloaded and executed.

var script = document.createElement("script");

script.setAttribute("src", url);
document.head.appendChild(script);

Application

The <script> tag is not subject to the same origin policy. Web pages can exploit this freedom to request cross-site data. JSONP, a technique for making cross-site AJAX-like requests, makes extensive use of dynamic script tag injection. Under the JSONP model, each AJAX request is replaced by a script tag injection.

The “async” Attribute

When a <script> tag is encountered, the browser stops what it is doing and begins downloading/executing the script. This default behavior is known as synchronous blocking. During this period of blocking, the page may seem unresponsive or slow to the user. To mitigate this problem, HTML5 introduced the “async” attribute for <script> tags. “async” is a Boolean attribute which, when specified, indicates that a script should unblock the rest of the page, and execute asynchronously. According to the specification, “async” should only be used with external script files. Unfortunately, “async” is not yet supported in Opera.  The following example shows how the “async” attribute is used.

<script src="file.js" async="async"></script>

Normally, “async” defaults to false. However, when dealing with dynamically injected scripts, the default value becomes true. This can lead to problems if scripts with interdependencies are inserted at the same time. For example, assume that a page injects a third-party library originating from a slow server. At (almost) the same time, the page also injects a script that makes calls to the library. Since the scripts are asynchronous, the second file could potentially get downloaded and executed before the library is available. The solution is to preserve the program order by setting “async” to false for both scripts. This concept is illustrated in the following example. In the example, the page will wait for the first script to load before moving on to the second script.

var library = document.createElement("script");
var local = document.createElement("script");

library.async = false;
local.async = false;
library.setAttribute("src", "remote-library-code.js");
local.setAttribute("src", "local-file.js");
document.head.appendChild(library);
document.head.appendChild(local);
// use the library code

The “defer” Attribute

As previously stated, <script> tags cause the browser to block the rest of the page while the script is processed. This can lead to problems if the script references DOM elements which haven’t finished loading yet. In this scenario, the DOM-related code is typically placed in an event handler such as window load or DOMContentLoaded. Another option is to postpone execution until the document has been parsed using the “defer” attribute. Like “async”, “defer” is a Boolean attribute that should only be used with external script files. The following example shows how “defer” works. This example requires an HTML file and a separate JavaScript file named defer.js. The HTML source is shown below.

<!DOCTYPE html>
<html lang="en">
<head>
  <title>defer Example</title>
  <meta charset="UTF-8" />
  <script src="defer.js" defer="defer"></script>
</head>
<body>
  <span id="message"></span>
</body>
</html>

The code for defer.js is shown below. If the “defer” attribute were not present, this code would fail because the DOM is not ready when the <span> element is accessed.

var span = document.getElementById("message");

span.textContent = "The DOM is ready for scripting!";

It is possible to specify both “async” and “defer” on the same <script> element. This is possible so that browsers that do not support “async” can fall back on the “defer” behavior instead of synchronous blocking. According to the specification, “defer” is overridden by “async”. Unfortunately, “defer” is also unsupported in Opera.

Performance Considerations

All of the examples on this page have shown <script> tags placed in the document’s head. This can actually degrade performance because the rest of the page is blocked while the scripts are processed. Obviously, the “defer” and “async” attributes offer one solution. Unfortunately, they are not supported everywhere yet. A second option is to move <script> tags to the bottom of the <body> tag whenever possible ― this is usually fine as long as the script does not call document.write().

Using external script files instead of inline scripts is another technique that often improves performance. This leads to smaller HTML files, at the expense of creating additional HTTP requests. However, script files are often shared among multiple HTML pages, and can be cached by the browser. The overall result is a smaller HTML download without the additional server requests. Also remember that scripts can be downloaded dynamically after the page is loaded.

Things to Remember

  • The <script> tag always requires a matching </script> tag.
  • The scripting language is specified by the “type” attribute. Do not use the “language” attribute. HTML5 defaults to “text/javascript”.
  • XHTML files should use external script files or CDATA sections to allow special characters.
  • Dynamic script tag injections allow cross-site resource requests.
  • The “async” attribute causes a script to execute asynchronously from the rest of the page. It can also preserve order for dynamically inserted scripts.
  • The “defer” attribute can postpone script execution until the document is ready.
  • Move <script> tags to the end of the <body> when possible.
  • Use external script files which can be cached and shared among pages.

Frequently Asked Questions (FAQs) about Script Tags

What is the significance of the “type” attribute in a script tag?

The “type” attribute in a script tag is used to specify the scripting language of the content. The default scripting language in HTML5 is JavaScript, so if the “type” attribute is not specified, the browser will interpret the content as JavaScript. However, if you’re using a different scripting language, you would need to specify it using the “type” attribute. For example, if you’re using VBScript, you would write type=”text/vbscript”.

Can I use multiple script tags in a single HTML document?

Yes, you can use multiple script tags in a single HTML document. Each script tag is processed in the order they appear in the document. This means that if one script depends on another, they must be placed in the correct order. However, using the “async” or “defer” attributes can alter this behavior.

What is the difference between “async” and “defer” in script tags?

Both “async” and “defer” are attributes that control how the script is executed. The “async” attribute means that the script is executed as soon as it’s available, without blocking the rendering of the page. The “defer” attribute, on the other hand, means that the script execution is deferred until the page has finished parsing. This can be useful for scripts that modify the DOM and depend on the full structure of the page being available.

How can I include an external JavaScript file using a script tag?

To include an external JavaScript file, you can use the “src” attribute in the script tag. The value of the “src” attribute should be the URL of the JavaScript file. For example, if you have a JavaScript file named “script.js” in the same directory as your HTML file, you would write src=”script.js”.

Can I write inline JavaScript code using script tags?

Yes, you can write inline JavaScript code using script tags. Any code placed between the opening and closing script tags will be executed by the browser. However, it’s generally recommended to place your JavaScript code in external files to improve the organization and maintainability of your code.

What is the purpose of the “charset” attribute in a script tag?

The “charset” attribute is used to specify the character encoding for the external script file. This can be useful when the script file uses a different character encoding than the HTML document. However, in most cases, this attribute is not necessary because the server should send the correct character encoding in the HTTP header.

Can I use script tags in the body of an HTML document?

Yes, you can use script tags anywhere in an HTML document. However, it’s common practice to place scripts at the bottom of the body element. This is because scripts can block the rendering of the page, so placing them at the bottom allows the rest of the page to load first.

What happens if a browser does not support JavaScript?

If a browser does not support JavaScript, it will simply ignore the script tags. You can use the “noscript” tag to provide alternative content for browsers that do not support JavaScript. The content inside the “noscript” tag will be displayed only if JavaScript is disabled or not supported.

Can I use comments inside script tags?

Yes, you can use comments inside script tags. In JavaScript, you can use // for single-line comments and /* … */ for multi-line comments. Comments are ignored by the browser and can be useful for explaining your code.

Can I use HTML entities inside script tags?

No, you cannot use HTML entities inside script tags. The content of a script tag is treated as raw text, not as HTML. If you need to include special characters in your script, you should use the appropriate JavaScript escape sequences.

Colin IhrigColin Ihrig
View Author

Colin Ihrig is a software engineer working primarily with Node.js. Colin is the author of Pro Node.js for Developers, and co-author of Full Stack JavaScript Development with MEAN. Colin is a member of the Node.js Technical Steering Committee, and a hapi core team member. Colin received his Bachelor of Science in Engineering, and Master of Science in Computer Engineering from the University of Pittsburgh in 2005 and 2008, respectively.

Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week