Question
Why Self-Closing Script Tags Don’t Work in HTML and XHTML
Question
In HTML, why do browsers not correctly recognize a self-closing script element like this?
<script src="foobar.js" />
But they do recognize this form:
<script src="foobar.js"></script>
What is the reason for this behavior? Does it conflict with the idea of XHTML support?
This behavior has been observed in browsers such as older versions of Internet Explorer.
Short Answer
By the end of this page, you will understand why script tags require a separate closing tag in normal HTML, why /> does not make a script element self-closing in HTML parsing, and how XHTML behaves differently only when the document is truly served as XHTML. You will also learn practical rules for writing script tags safely across browsers.
Concept
The core idea
The issue is not really about JavaScript. It is about how browsers parse HTML.
In HTML, the <script> element is not a void element. That means it is expected to have both:
- an opening tag
- a closing tag
So this is valid HTML:
<script src="foobar.js"></script>
But this is not treated as a self-closing script element in HTML:
<script src="foobar.js" />
Why /> does not work here
In HTML syntax, the slash in /> is not a universal "self-close this tag" instruction for every element. HTML only allows certain elements to omit closing tags because they are void elements, such as:
<br><img><input><meta>
Mental Model
Think of the HTML parser like a reader following a grammar book.
- Some tags are like single-word commands:
<br>or<img> - Some tags are like paired brackets:
<script> ... </script>
<script> belongs to the second group.
Writing:
<script src="foobar.js" />
in HTML is like opening a bracket and hoping the reader will guess it closes itself. But the grammar rules for HTML do not allow that for script.
In XML/XHTML, the grammar is stricter and /> has a real self-closing meaning. But only if the browser is actually reading the document as XML, not as ordinary HTML.
So the key mental model is:
- HTML mode:
scriptneeds</script> - XML/XHTML mode:
/>can self-close, but only under XML parsing rules
Syntax and Examples
Correct HTML syntax
Use a normal opening and closing script tag:
<script src="foobar.js"></script>
Incorrect for normal HTML parsing
<script src="foobar.js" />
In HTML, this does not reliably self-close the element.
Inline script example
<script>
const message = "Hello";
console.log(message);
</script>
This works because the parser clearly sees where the script starts and ends.
External script example
<!doctype html>
<html>
<head>
<script =>
Page loaded
Step by Step Execution
Example to trace
Consider this HTML:
<!doctype html>
<html>
<body>
<script src="app.js" />
<p>Hello</p>
</body>
</html>
What the HTML parser does
Step 1: Reads <script src="app.js" />
Because the document is being parsed as HTML, the parser sees a script start tag.
Step 2: Ignores the idea of self-closing for script
The trailing / does not make script a valid self-closing HTML element.
Step 3: Keeps the script element open
The parser expects a real closing tag:
</>
Real World Use Cases
Where this matters
Including JavaScript files in web pages
This is the most direct use case:
<script src="main.js"></script>
If you use self-closing syntax in HTML, the browser may parse the page incorrectly.
Server-rendered templates
In template engines such as EJS, Handlebars, Twig, or JSP, developers often generate script tags dynamically. Using proper closing tags avoids cross-browser parsing bugs.
CMS platforms
Systems like WordPress, Drupal, or custom CMS tools inject scripts into pages. Incorrect markup can break analytics, widgets, or app initialization.
Embedded third-party tools
Chat widgets, tracking scripts, ad code, and payment integrations are often inserted with script tags. These snippets must use standard HTML syntax to work reliably.
Legacy browser support
Older browsers were especially sensitive to parser differences. Explicit closing tags were necessary for compatibility.
Real Codebase Usage
How developers use this in real projects
Standard script inclusion
Developers almost always write:
<script src="bundle.js"></script>
This is the normal, compatible pattern.
Template-generated assets
In production code, asset helpers often generate script tags:
<script src="/static/app.js"></script>
Frameworks and build tools output full opening and closing tags because that is the correct HTML form.
Guarding against parsing bugs
Teams avoid XHTML-style self-closing syntax in HTML templates because it can silently break document structure.
Linting and formatting
HTML formatters and linters usually preserve script with explicit closing tags. This helps keep markup standards-compliant and consistent.
Component and SSR environments
Even in modern component systems, rendered HTML output still follows HTML parsing rules. So although JSX may look XML-like, the generated HTML for a script element still needs proper structure.
Example in JSX:
Common Mistakes
1. Assuming /> self-closes every HTML tag
Broken example:
<script src="app.js" />
Why it is wrong:
scriptis not a void element in HTML- the parser still expects
</script>
Fix:
<script src="app.js"></script>
2. Confusing XHTML-looking syntax with actual XHTML parsing
Beginners often think that writing HTML like this means the browser will parse it as XML:
<!doctype html>
<html>
<head>
<script src="app.js" />
</head>
</html>
It does not. If the page is served as , it is parsed as HTML.
Comparisons
HTML vs XHTML parsing
| Topic | HTML | XHTML/XML |
|---|---|---|
| Parsing model | HTML parser | XML parser |
Meaning of /> | Not a universal self-close for all tags | Self-closing syntax is meaningful |
script tag | Requires </script> | Can be self-closed syntactically if valid in XML context |
| Common content type | text/html | application/xhtml+xml |
| Browser behavior | Follows HTML rules | Follows XML rules |
Void elements vs normal elements
Cheat Sheet
Quick rules
- In HTML, always write external scripts like this:
<script src="app.js"></script>
- Do not rely on this in HTML:
<script src="app.js" />
scriptis not a void element.img,br,input,meta, andlinkare void elements.- XHTML rules only apply when the document is actually parsed as XML/XHTML.
- A page served as
text/htmluses HTML parsing rules, even if the markup looks XML-like.
Safe default
If you are writing web pages for browsers, use:
<script></script>
or
FAQ
Why does <script src="file.js" /> fail in HTML?
Because HTML does not treat script as a self-closing element. The parser expects a real </script> closing tag.
Is this only a problem in old Internet Explorer?
No. Older IE made it easier to notice, but the underlying issue comes from HTML parsing rules.
Does XHTML allow self-closing script tags?
In true XML/XHTML parsing, /> has self-closing meaning. But that only applies if the document is actually served and parsed as XHTML/XML.
If my document looks like XHTML, is that enough?
No. What matters is how the browser parses it. If it is served as text/html, HTML rules apply.
Why is img allowed to self-close but script is not?
Because img is a void element in HTML, while script is a normal element that requires a closing tag.
Should I always close script tags explicitly?
Yes. In normal HTML documents, that is the correct and safe approach.
Does this apply to inline scripts too?
Yes. Inline scripts also require an explicit closing </script> tag in HTML.
Mini Project
Description
Build a small HTML page that loads an external JavaScript file correctly and demonstrates why proper script tag syntax matters. This project helps you practice using valid HTML script inclusion and observing browser behavior safely.
Goal
Create a page that loads an external script and updates the page content using the correct script tag syntax.
Requirements
Create an index.html file with a heading and an empty paragraph element.
Create an app.js file that changes the paragraph text when the script runs.
Include app.js in index.html using a correctly closed script tag.
Open the page in a browser and confirm that the text updates.
Optionally test the broken self-closing form and observe that it is unreliable.
Keep learning
Related questions
Can You Style Half a Character in CSS? Text Effects with CSS and JavaScript
Learn how to style half of a character using CSS and JavaScript, including overlay techniques for dynamic text effects.
Check If a Checkbox Is Checked with jQuery
Learn how to check whether a checkbox is checked in jQuery using the correct selector, with examples, mistakes, and practical patterns.
Convert HTML and CSS to PDF in PHP: Options, Limits, and Practical Approaches
Learn how HTML-to-PDF conversion works in PHP, why CSS support varies, and how to choose a practical approach for Linux web servers.