Skip to content

Linter Rule: Require explicit closing tags

Rule: html-require-closing-tags

Description

Disallow the omission of optional closing tags for HTML elements where the closing tag is technically optional according to the HTML specification. This rule flags elements that have an HTMLOmittedCloseTagNode as their close tag.

Rationale

While HTML allows certain closing tags to be omitted (implicitly closed by sibling elements or parent closing), explicit closing tags improve code readability and maintainability. They make the document structure clear at a glance and reduce ambiguity about where elements end.

Explicit closing tags also:

  • Make templates easier to understand for developers unfamiliar with HTML's implicit closing rules
  • Reduce potential for subtle bugs when refactoring or moving code
  • Improve consistency across the codebase
  • Make diffs cleaner when adding content to elements

Elements with Optional Closing Tags

This rule would flag elements that have omitted closing tags:

  • <li> - list items
  • <dt>, <dd> - definition list terms and descriptions
  • <p> - paragraphs
  • <option>, <optgroup> - select options and groups
  • <thead>, <tbody>, <tfoot> - table sections
  • <tr> - table rows
  • <td>, <th> - table cells
  • <colgroup> - table column groups
  • <rt>, <rp> - ruby annotations

Examples

✅ Good

Explicit closing tags:

erb
<ul>
  <li>Item 1</li>
  <li>Item 2</li>
  <li>Item 3</li>
</ul>
erb
<dl>
  <dt>Term 1</dt>
  <dd>Definition 1</dd>
  <dt>Term 2</dt>
  <dd>Definition 2</dd>
</dl>
erb
<table>
  <thead>
    <tr>
      <th>Header 1</th>
      <th>Header 2</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Cell 1</td>
      <td>Cell 2</td>
    </tr>
  </tbody>
</table>
erb
<select>
  <option>Option 1</option>
  <option>Option 2</option>
  <option>Option 3</option>
</select>
erb
<div>
  <p>Paragraph 1</p>
  <p>Paragraph 2</p>
</div>

🚫 Bad

Omitted closing tags (implicitly closed):

erb
<ul>
  <li>Item 1
Element `<li>` at (2:3) has its closing tag omitted. While valid HTML, consider adding an explicit `</li>` closing tag at (3:2) for clarity, or set `strict: false` to allow this. (`OMITTED_CLOSING_TAG_ERROR`) (parser-no-errors)
<li>Item 2
Missing explicit closing tag for `<li>`. Use `</li>` instead of relying on implicit tag closing. (html-require-closing-tags)
Element `<li>` at (3:3) has its closing tag omitted. While valid HTML, consider adding an explicit `</li>` closing tag at (4:2) for clarity, or set `strict: false` to allow this. (`OMITTED_CLOSING_TAG_ERROR`) (parser-no-errors)
<li>Item 3
Missing explicit closing tag for `<li>`. Use `</li>` instead of relying on implicit tag closing. (html-require-closing-tags)
Element `<li>` at (4:3) has its closing tag omitted. While valid HTML, consider adding an explicit `</li>` closing tag at (5:0) for clarity, or set `strict: false` to allow this. (`OMITTED_CLOSING_TAG_ERROR`) (parser-no-errors)
</ul>
Missing explicit closing tag for `<li>`. Use `</li>` instead of relying on implicit tag closing. (html-require-closing-tags)
erb
<dl>
  <dt>Term 1
Element `<dt>` at (2:3) has its closing tag omitted. While valid HTML, consider adding an explicit `</dt>` closing tag at (3:2) for clarity, or set `strict: false` to allow this. (`OMITTED_CLOSING_TAG_ERROR`) (parser-no-errors)
<dd>Definition 1
Missing explicit closing tag for `<dt>`. Use `</dt>` instead of relying on implicit tag closing. (html-require-closing-tags)
Element `<dd>` at (3:3) has its closing tag omitted. While valid HTML, consider adding an explicit `</dd>` closing tag at (4:2) for clarity, or set `strict: false` to allow this. (`OMITTED_CLOSING_TAG_ERROR`) (parser-no-errors)
<dt>Term 2
Missing explicit closing tag for `<dd>`. Use `</dd>` instead of relying on implicit tag closing. (html-require-closing-tags)
Element `<dt>` at (4:3) has its closing tag omitted. While valid HTML, consider adding an explicit `</dt>` closing tag at (5:2) for clarity, or set `strict: false` to allow this. (`OMITTED_CLOSING_TAG_ERROR`) (parser-no-errors)
<dd>Definition 2
Missing explicit closing tag for `<dt>`. Use `</dt>` instead of relying on implicit tag closing. (html-require-closing-tags)
Element `<dd>` at (5:3) has its closing tag omitted. While valid HTML, consider adding an explicit `</dd>` closing tag at (6:0) for clarity, or set `strict: false` to allow this. (`OMITTED_CLOSING_TAG_ERROR`) (parser-no-errors)
</dl>
Missing explicit closing tag for `<dd>`. Use `</dd>` instead of relying on implicit tag closing. (html-require-closing-tags)
erb
<table>
  <thead>
Element `<thead>` at (2:3) has its closing tag omitted. While valid HTML, consider adding an explicit `</thead>` closing tag at (6:2) for clarity, or set `strict: false` to allow this. (`OMITTED_CLOSING_TAG_ERROR`) (parser-no-errors)
<tr>
Element `<tr>` at (3:5) has its closing tag omitted. While valid HTML, consider adding an explicit `</tr>` closing tag at (6:2) for clarity, or set `strict: false` to allow this. (`OMITTED_CLOSING_TAG_ERROR`) (parser-no-errors)
<th>Header 1
Element `<th>` at (4:7) has its closing tag omitted. While valid HTML, consider adding an explicit `</th>` closing tag at (5:6) for clarity, or set `strict: false` to allow this. (`OMITTED_CLOSING_TAG_ERROR`) (parser-no-errors)
<th>Header 2
Missing explicit closing tag for `<th>`. Use `</th>` instead of relying on implicit tag closing. (html-require-closing-tags)
Element `<th>` at (5:7) has its closing tag omitted. While valid HTML, consider adding an explicit `</th>` closing tag at (6:2) for clarity, or set `strict: false` to allow this. (`OMITTED_CLOSING_TAG_ERROR`) (parser-no-errors)
<tbody>
Missing explicit closing tag for `<thead>`. Use `</thead>` instead of relying on implicit tag closing. (html-require-closing-tags)
Missing explicit closing tag for `<tr>`. Use `</tr>` instead of relying on implicit tag closing. (html-require-closing-tags)
Missing explicit closing tag for `<th>`. Use `</th>` instead of relying on implicit tag closing. (html-require-closing-tags)
Element `<tbody>` at (6:3) has its closing tag omitted. While valid HTML, consider adding an explicit `</tbody>` closing tag at (10:0) for clarity, or set `strict: false` to allow this. (`OMITTED_CLOSING_TAG_ERROR`) (parser-no-errors)
<tr>
Element `<tr>` at (7:5) has its closing tag omitted. While valid HTML, consider adding an explicit `</tr>` closing tag at (10:0) for clarity, or set `strict: false` to allow this. (`OMITTED_CLOSING_TAG_ERROR`) (parser-no-errors)
<td>Cell 1
Element `<td>` at (8:7) has its closing tag omitted. While valid HTML, consider adding an explicit `</td>` closing tag at (9:6) for clarity, or set `strict: false` to allow this. (`OMITTED_CLOSING_TAG_ERROR`) (parser-no-errors)
<td>Cell 2
Missing explicit closing tag for `<td>`. Use `</td>` instead of relying on implicit tag closing. (html-require-closing-tags)
Element `<td>` at (9:7) has its closing tag omitted. While valid HTML, consider adding an explicit `</td>` closing tag at (10:0) for clarity, or set `strict: false` to allow this. (`OMITTED_CLOSING_TAG_ERROR`) (parser-no-errors)
</table>
Missing explicit closing tag for `<tbody>`. Use `</tbody>` instead of relying on implicit tag closing. (html-require-closing-tags)
Missing explicit closing tag for `<tr>`. Use `</tr>` instead of relying on implicit tag closing. (html-require-closing-tags)
Missing explicit closing tag for `<td>`. Use `</td>` instead of relying on implicit tag closing. (html-require-closing-tags)
erb
<select>
  <option>Option 1
Element `<option>` at (2:3) has its closing tag omitted. While valid HTML, consider adding an explicit `</option>` closing tag at (3:2) for clarity, or set `strict: false` to allow this. (`OMITTED_CLOSING_TAG_ERROR`) (parser-no-errors)
<option>Option 2
Missing explicit closing tag for `<option>`. Use `</option>` instead of relying on implicit tag closing. (html-require-closing-tags)
Element `<option>` at (3:3) has its closing tag omitted. While valid HTML, consider adding an explicit `</option>` closing tag at (4:2) for clarity, or set `strict: false` to allow this. (`OMITTED_CLOSING_TAG_ERROR`) (parser-no-errors)
<option>Option 3
Missing explicit closing tag for `<option>`. Use `</option>` instead of relying on implicit tag closing. (html-require-closing-tags)
Element `<option>` at (4:3) has its closing tag omitted. While valid HTML, consider adding an explicit `</option>` closing tag at (5:0) for clarity, or set `strict: false` to allow this. (`OMITTED_CLOSING_TAG_ERROR`) (parser-no-errors)
</select>
Missing explicit closing tag for `<option>`. Use `</option>` instead of relying on implicit tag closing. (html-require-closing-tags)
erb
<div>
  <p>Paragraph 1
Element `<p>` at (2:3) has its closing tag omitted. While valid HTML, consider adding an explicit `</p>` closing tag at (3:2) for clarity, or set `strict: false` to allow this. (`OMITTED_CLOSING_TAG_ERROR`) (parser-no-errors)
<p>Paragraph 2
Missing explicit closing tag for `<p>`. Use `</p>` instead of relying on implicit tag closing. (html-require-closing-tags)
Element `<p>` at (3:3) has its closing tag omitted. While valid HTML, consider adding an explicit `</p>` closing tag at (4:0) for clarity, or set `strict: false` to allow this. (`OMITTED_CLOSING_TAG_ERROR`) (parser-no-errors)
</div>
Missing explicit closing tag for `<p>`. Use `</p>` instead of relying on implicit tag closing. (html-require-closing-tags)

References

Released under the MIT License.