You are not required to close your <p>, <li>, <img>, or <br> tags in HTML

Are you an author writing HTML?

Just so we’re clear: Not XHTML. HTML. Without the X.

If you are, repeat after me, because apparently this bears repeating (after the title):

You are not required to close your <p>, <li>, <img>, or <br> tags in HTML.

(The same applies to over a dozen other elements but these are the most common ones.)

There are a number of reasons it is good practice to do so (which I’ll get to later in this article), but it is not wrong or inherently bad practice not to do so with elements with optional end tags or elements without end tags (believe it or not, these exist — they’re called void elements). Browsers do not treat missing optional end tags as errors that need to be recovered from.

Anyone telling you otherwise about these elements was unfortunately misinformed by the one before them. Please correct them, perhaps by pointing them to this article; chances are you were referred here by me or someone else for this very reason.

For the sake of convenience, “HTML5” refers to either WHATWG HTML (the living standard) or W3C HTML5, whichever you’re personally more comfortable with. None of the differences between the two are pertinent to this article, so I won’t even make any references to either specification. But I consider the living spec by WHATWG canon, so all spec links will point to that.

Table of contents

  1. Background
  2. The rules in HTML, and XHTML
  3. Best practices in HTML

Background

I see the following examples of misinformation being spread almost every day on Stack Overflow, in both comments and answers (that get upvoted!):

As well as the following examples of confused comments, directed at me when I post HTML snippets with optional tags omitted for brevity, or when I state the same thing I just massively did above:

These are all adapted from real comments; that last one was from just this week. Now, spreading misinformation is one thing. But spreading misinformation under the guise of “the guy is learning” (and attempting to school me about “strict coding standards”1)? Sorry, but I can’t allow that. That’s why I finally got around to writing this article after sitting on it for years — for the benefit of those who are learning.

(BTW, no, those two questions aren’t in the same category at all. The DOCTYPE is mandatory, period. Self-closing void element tags in HTML using the /> syntax is entirely a matter of personal preference — I cover this in full detail below.)

These misconceptions appear to stem from the XHTML fad of the 00s, before HTML5 emerged. XHTML, being based on XML as opposed to SGML, is notorious for being author-unfriendly due to its strictness, requiring start and end tags for all elements (including void elements using the /> syntax) and quotes around attribute values, as well as forbidding minimization of Boolean attributes such as checked, disabled and required. (Nevertheless, everyone attempted to write XHTML, although almost no one ended up actually writing and serving true XHTML.) It would seem that many authors who don’t know better have mistakenly believed that these rules carry over to HTML5 as they moved away from XHTML, and the misinformation has been spreading ever since.

The rules in HTML, and XHTML

Let’s start with some markup examples. The following fragments are valid HTML and well-formed XHTML:

<p>This paragraph has an end tag.</p>
<p>So does this one.</p>
<ol>
    <li>This list item has an end tag.</li>
    <li>So does this one.</li>
</ol>

Stuff you’re probably used to, where every element has a matching pair of start and end tags.

On the other hand, if the following fragments make you uncomfortable, relax — they may not be well-formed XHTML, but they are valid HTML, because the end tags of p and li are optional and browsers are told exactly when to implicitly close a previously open element (again, this is not error recovery!):

<p>This paragraph does not have an end tag.
<p>Neither does this one.
<ol>
    <li>This list item does not have an end tag.
    <li>Neither does this one.
</ol>

This is actually how I was taught HTML growing up! According to the Neopets HTML Guide, <p> tags were simply a way to start new paragraphs of text, and similarly <li> tags represented the bullets or numbers themselves. Following this logic, end tags weren’t needed. In fact, the original 1993 draft of HTML that pre-dates 1995’s RFC 1866 (HTML 2.0) described both p and li in nearly the exact same way as Neopets did, and defined them as having an empty content model, just like br, meaning they originally didn’t have end tags either! So, it actually baffles me any time someone claims that p and li have “always required” end tags. Au contraire, they never did, and never have in over 20 years. But I digress; enough about my childhood.

In situations where line breaks and indentation are involved, the only difference between these two pairs of fragments is how inter-element whitespace is treated: there is no inter-element whitespace between each pair of elements without their end tags — the whitespace all becomes part of the text content of the first element in each pair. This does have certain implications in CSS, particularly in inline layout where whitespace processing plays a crucial, if not central, role.

Next, let’s look at the shortcut “self-closing” syntax />. This syntax comes from XML, so it follows that it’s used in XHTML. So, if HTML5 is a language in its own right and neither based on SGML nor XML, what is /> doing in HTML5? It’s there for exactly one reason: ease of migration from XHTML.2 You have an XHTML document with all these void elements closed with the /> syntax as expected in XHTML. Migrating it to HTML5, provided there are no other compatibility issues such as the use of obsolete elements like acronym, is as easy as switching the DOCTYPE declaration to <!DOCTYPE html>. Bam. Done.

Alright, so, I keep mentioning void elements. What is a void element? A void element in HTML is an element that has a start tag and no end tag (and therefore no content, hence “void”). Common examples of void elements include br, hr, img, input, link, and meta. A full list can be found in the spec. In previous versions of HTML, they were known as empty elements, however XML and now HTML make a distinction between empty elements and void elements, so the term to use going forward is “void elements”. In summary (these words are my own, taken from the link right before this sentence):

  • An empty element is one that has no content, regardless of whether it is allowed to have content in the first place.
  • A void element is one that cannot have any content.

Additionally, it can be said that all void elements are empty elements by definition, but an empty element does not necessarily represent a void element.

Now that you understand where the /> syntax came from and why it’s in use today, let’s look at some examples. The following fragment is valid HTML5 and well-formed XHTML, but not valid in any older version of HTML:

<p><img src="lightbulb.jpg" alt="" /><br />
I'm aware that the use of <code>br</code> here is incorrect;
this is simply for illustrative purposes.</p>

Again, stuff you’re probably used to, especially if you were taught to always self-close your void element tags using />.

But, as the title of this article states, you are not required to do that. The following fragment is not well-formed XHTML, but it is valid in all versions of HTML:

<p><img src="lightbulb.jpg" alt=""><br>
I'm aware that the use of <code>br</code> here is incorrect;
this is simply for illustrative purposes.</p>

Before I go on, you may also have noticed that there has always been a space before the /> in HTML5 and XHTML, even in the example fragments in this article. This is also not required in either dialect, in the sense that <br/> validates just as well as <br /> does.3 However, it is a tradition dating back nearly 20 years (again!), and the reason for this tradition was that Netscape Navigator 3 (you read that right, not even Netscape 4, but Netscape 3) would choke on <br/>.

Yes, an actual browser bug. I’m totally fine with tradition that has roots in actual cross-browser problems, because while those problems may no longer be relevant today, they were once upon a time, so people didn’t really have a choice back then. In contrast, no browser in the history of XHTML has ever treated the /> syntax itself incorrectly — evidently, NN3 handled that just fine, provided you included the space — so there really is no excuse for claiming that /> is required for void elements in HTML.

Speaking of which, best practices to come shortly, I promise. (You can also skip straight over right now if you prefer, because what follows is advanced stuff.)

For now, this is where things get really interesting. The following fragment is well-formed XHTML4, but not valid in any version of HTML:

<div />
<p />
<input type="text"></input>

First, the </input> end tag is allowed in XHTML because XML always permits using either an explicit end tag or the /> syntax to close an empty element. However, because input is a void element, it does not have an end tag in HTML, and therefore specifying an explicit one is forbidden.

But because the /> syntax comes from XML and not SGML, even though it exists in HTML5 solely to ease migration from XHTML, apart from foreign elements it is completely meaningless in HTML5 and invalid in all older, SGML-based versions of HTML. And since void elements don’t have end tags, whether or not you self-close them is entirely a matter of personal preference.

What about non-void elements? Well, not only is <div /> treated exactly the same as <div> (resulting in a div that is missing an end tag), but the same fragment above actually produces different DOM trees in HTML and XHTML (when served as application/xhtml+xml as intended) for this reason.

In the HTML DOM, the input becomes a child of the p, which in turn becomes a child of the div (inter-element whitespace not significant for the purposes of this example; explicit end tags added for clarity):

<div>
    <p>
        <input type="text">
    </p>
</div>

In the XHTML DOM, the div, p and input are empty siblings of one another (again, explicit end tags added for clarity):

<div></div>
<p></p>
<input type="text"></input>

For most authors, this will never be a problem since anyone who tries to use /> to self-close non-void elements tags in text/html will quickly find out that it doesn’t work anyway. (They probably spend a tad longer confused if writing “XHTML”, i.e. XHTML that’s not served as application/xhtml+xml as intended, but as mentioned almost no one ever serves it with the correct MIME type to begin with, so again this really is a non-issue.)

Alright! Now for best practices. What you can do, and what you should do when in doubt.

Best practices in HTML

Disclaimer: this is just my opinion, not gospel. But, if I do say so myself, I feel it’s advice worth considering. Having said that, if you have any views of your own that you’d like to share, feel free to leave a comment and we can discuss, so long as we promise to be respectful to one another.

Here’s what I recommend to anyone building a new site, whether they’re a new or seasoned HTML author: Be consistent. There is nothing wrong with leaving out optional end tags where permissible, and/or writing void element tags with />, but I recommend that you either do it consistently, or don’t do it at all (also consistently). Here’s my breakdown:

I do want to highlight a somewhat interesting case. While the following fragment validates as HTML5:

<input type=checkbox checked />

… it does seem rather unusual, doesn’t it? It’s a mix of both HTML syntax (unquoted attribute values, minimized Boolean attributes) and XML syntax (/>). Personally I think using /> kinda partially cancels out the brevity afforded by leaving out attribute quotes. And while it does also contradict using minimized attributes in principle, at least we can make a really strong case for doing that since you can save yourself needlessly duplicating keystrokes and bytes. But yeah, I’d say just quote all your attribute values if you’re going to the trouble of using />:

<input type="checkbox" checked />

As mentioned in the very beginning of this article, any time someone yells at you to close your <p>, <li>, <img>, or <br> tags because “your markup is invalid”, and you haven’t stated outright that you’re writing XHTML, refer them to this article, and don’t worry about it. You are doing nothing wrong. Even if you meant to include the end tags (perhaps based on my suggestions above) and simply left some out by accident, that’s a separate issue altogether. My point is that it’s not invalid as many seem to claim.

And here’s what I recommend when migrating an existing site to HTML5: If it ain’t broke, don’t fix it. In the vast majority of cases, provided your site already validates according to whatever DTD it had before, switching the DOCTYPE to <!DOCTYPE html> should be enough. It doesn’t matter whether the site was previously XHTML or an older version of HTML. Roll with it. HTML5 is cool like that, by design.

When the time comes for a redesign, then you can throw out everything you learned about XHTML and just focus on writing standards-compliant HTML5 — which does not necessitate using the /> syntax or expanding Boolean attributes. Don’t let anyone tell you otherwise.


  1. I built and maintained over half a dozen sites and WordPress themes that remained entirely Valid XHTML 1.0 Strict for over 10 years combined. I think it’s safe to say I know strict markup better than you do. (Any WordPress theme developer from that era knows that the things are a nightmare to make XHTML 1.0 Strict-compliant.) 
  2. See also the obsolete polyglot markup TR
  3. In fact, the vast majority of other XML documents don’t include the space because it’s considered unnatural to do so. 
  4. It’s invalid XHTML 1.0, though, in the context of the body element because it doesn’t permit input being a child of body. It’s also invalid in HTML 4 and older. 
  5. Unless you really like XHTML — I for one would probably call myself an XHTML apologist. 

1 comment

Add a comment

Things to keep in mind: