The Rules of JSX (Part 2): Closing All Tags #21
📖 Introduction
In the previous article, we covered the first major rule of JSX: a component must return a single root element. Now, we turn to another strict rule that comes from JSX's XML-like nature: every tag must be explicitly closed.
In HTML, you can sometimes get away with omitting a closing tag for certain elements. JSX, however, is much stricter. This rule ensures that your code is unambiguous and less prone to hard-to-find bugs. This article will cover how and why you must close every JSX tag.
📚 Prerequisites
Before we begin, please ensure you have a solid grasp of the following concepts:
- Basic HTML: Familiarity with standard HTML tags, including self-closing tags like
<img>
and<br>
. - Basic JSX Syntax: You should be comfortable writing simple JSX elements.
🎯 Article Outline: What You'll Master
In this article, you will learn:
- ✅ The XML Heritage of JSX: Understanding why JSX inherits strict closing tag rules from XML.
- ✅ Closing Standard Tags: The correct way to close elements that have content.
- ✅ Self-Closing Tags: How to properly close elements that have no children, like
<img>
,<input>
, and<br>
. - ✅ Closing Your Own Components: Applying the self-closing syntax to your custom React components.
🧠 Section 1: Why Every Tag Must Be Closed
JSX's syntax is based on XML (eXtensible Markup Language), not HTML. A key feature of XML is its strictness. It's designed to be parsed unambiguously by machines, which means there are no optional closing tags. Every opening tag must have a corresponding closing tag.
HTML, on the other hand, is more lenient to make it easier for humans to write. A browser's HTML parser will often correct mistakes, like automatically closing a <p>
tag when it sees a new one.
The JSX transpiler (Babel) does not do this. It requires well-formed, valid code to correctly convert it into React.createElement()
calls. An unclosed tag is a syntax error.
The Problem in Practice: This HTML might render correctly in a browser, but it is invalid JSX:
// This will cause an error!
function ImageList() {
return (
<>
<p>Look at these images:
<img src="image1.jpg">
<img src="image2.jpg">
</>
);
}
This code will fail to compile because the <p>
and <img>
tags are not closed.
💻 Section 2: How to Close Tags in JSX
There are two ways to close a tag, depending on whether it has child content.
2.1 - Tags with Children
For any element that wraps around other elements or text, you must provide an explicit closing tag.
// code-block-1.jsx
// Correctly closed tags
function Article() {
return (
<div>
<p>This is a paragraph with a closing tag.</p>
<ul>
<li>List item 1</li>
<li>List item 2</li>
</ul>
</div>
);
}
This is straightforward and matches how you would typically write well-formed HTML.
2.2 - Self-Closing Tags
In HTML, some elements are "void" or "empty," meaning they cannot have children. Common examples include <img>
, <input>
, <br>
, and <hr>
. In HTML, you can write them as <br>
or <img>
.
In JSX, these tags must be "self-closed" by adding a forward slash /
before the final greater-than sign >
.
Correcting the invalid example from Section 1:
// code-block-2.jsx
// Now this is valid JSX!
function ImageList() {
return (
<>
<p>Look at these images:</p>
<img src="image1.jpg" alt="First" />
<img src="image2.jpg" alt="Second" />
</>
);
}
Notice that the <p>
tag now has a closing </p>
tag, and both <img>
tags are self-closed with a />
.
🛠️ Section 3: Self-Closing Your Custom Components
This rule also applies to your own React components. If a component doesn't need to wrap any other JSX (i.e., it doesn't have any children
), you should use the self-closing syntax. It's cleaner and signals to other developers that the component stands alone.
Example:
Let's say you have a UserProfile
component and a Greeting
component.
// UserProfile.jsx
function UserProfile({ user }) {
return (
<div>
<img src={user.avatarUrl} alt={user.name} />
<p>{user.name}</p>
</div>
);
}
// Greeting.jsx
function Greeting({ name }) {
return <h1>Hello, {name}!</h1>;
}
// App.jsx
import UserProfile from './UserProfile';
import Greeting from './Greeting';
function App() {
const user = { name: 'Hedy', avatarUrl: '...' };
return (
<>
{/* These components have no children, so they are self-closed */}
<Greeting name={user.name} />
<UserProfile user={user} />
</>
);
}
Using <Greeting />
and <UserProfile />
is much cleaner than writing <Greeting></Greeting>
when there's nothing to put inside.
✨ Section 4: Best Practices
Best Practices:
- Always Self-Close Empty Elements: Make it a habit to immediately self-close any element that won't have children, such as
<img>
,<input>
,<hr>
,<br>
, and childless components. - Rely on Your Linter: A good linter will immediately flag unclosed tags as errors, helping you catch these mistakes before you even run your code.
- Format for Readability: For components with many props, it's common practice to put each prop on a new line, which makes the self-closing
/>
at the end very clear.
// Readable formatting for a self-closing tag with many props
<img
className="avatar"
src={user.imageUrl}
alt={'Photo of ' + user.name}
style={{ width: 100, height: 100 }}
/>
💡 Conclusion & Key Takeaways
The rule that all tags must be closed is a core principle of JSX that ensures your code is explicit, predictable, and free from the parsing ambiguities that can occur in HTML.
Let's summarize the key takeaways:
- JSX is Strict: Unlike HTML, JSX requires every tag to be closed.
- Two Ways to Close: Use a closing tag (
</p>
) for elements with children, and a self-closing tag (<br />
) for elements without children. - Applies to All Tags: This rule applies equally to standard HTML elements and your own custom React components.
- Cleaner Code: Using the self-closing syntax for empty elements makes your code more concise and readable.
Challenge Yourself:
Take an existing piece of simple HTML (from a website, a template, etc.) that has a few unclosed tags (like <img>
, <br>
, or <p>
without a closing tag). Paste it into a React component and fix all the errors until it becomes valid JSX. This is a great way to train your eye to spot these issues.
➡️ Next Steps
You now have a firm grasp of the most important syntax rules of JSX. In the final article of this series, "Common JSX Patterns and Pitfalls", we will cover a few remaining topics, such as how to write comments in JSX and how to avoid some common mistakes that trip up beginners.
Thank you for your dedication. Stay curious, and happy coding!
glossary
- Self-Closing Tag: A JSX tag that is closed within itself using a forward slash before the final bracket (e.g.,
<img />
). It is used for elements that do not have any children. - XML (eXtensible Markup Language): A markup language with a strict set of rules for encoding documents in a format that is both human-readable and machine-readable. JSX inherits its strictness from XML.