@codelaw/rules-html 0.0.0-stage → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/LICENSE +23 -0
  2. package/NOTICE +24 -0
  3. package/README.md +166 -2
  4. package/codelaw-pack.toml +6 -0
  5. package/corpus.toml +76 -0
  6. package/data/html/elements.json +4892 -0
  7. package/data/html/entities.json +1 -0
  8. package/data/html/input-attributes.json +227 -0
  9. package/package.json +14 -4
  10. package/presets/html/a11y.toml +29 -0
  11. package/presets/html/conventions.toml +6 -0
  12. package/presets/html/document.toml +8 -0
  13. package/presets/html/recommended.toml +67 -0
  14. package/rules/html/area-alt.md +48 -0
  15. package/rules/html/aria-hidden-body.md +39 -0
  16. package/rules/html/aria-label-misuse.md +42 -0
  17. package/rules/html/attribute-allowed-values.cases.md +31 -0
  18. package/rules/html/attribute-allowed-values.md +41 -0
  19. package/rules/html/attribute-misuse.md +39 -0
  20. package/rules/html/autocomplete-password.md +41 -0
  21. package/rules/html/button-type.cases.md +28 -0
  22. package/rules/html/button-type.md +35 -0
  23. package/rules/html/close-attr.md +33 -0
  24. package/rules/html/close-order.cases.md +38 -0
  25. package/rules/html/close-order.md +47 -0
  26. package/rules/html/deprecated.md +39 -0
  27. package/rules/html/doctype-html.md +36 -0
  28. package/rules/html/element-name.cases.md +21 -0
  29. package/rules/html/element-name.md +42 -0
  30. package/rules/html/element-permitted-content.cases.md +54 -0
  31. package/rules/html/element-permitted-content.md +45 -0
  32. package/rules/html/element-permitted-occurrences.md +45 -0
  33. package/rules/html/element-permitted-order.md +44 -0
  34. package/rules/html/element-permitted-parent.cases.md +11 -0
  35. package/rules/html/element-permitted-parent.md +43 -0
  36. package/rules/html/element-required-ancestor.md +45 -0
  37. package/rules/html/element-required-attributes.md +44 -0
  38. package/rules/html/element-required-content.cases.md +23 -0
  39. package/rules/html/element-required-content.md +43 -0
  40. package/rules/html/empty-heading.md +40 -0
  41. package/rules/html/empty-title.md +39 -0
  42. package/rules/html/fieldset-legend.md +44 -0
  43. package/rules/html/form-dup-name.cases.md +38 -0
  44. package/rules/html/form-dup-name.md +48 -0
  45. package/rules/html/form-submit.md +44 -0
  46. package/rules/html/heading-level.cases.md +26 -0
  47. package/rules/html/heading-level.md +44 -0
  48. package/rules/html/hidden-focusable.cases.md +23 -0
  49. package/rules/html/hidden-focusable.md +40 -0
  50. package/rules/html/img-alt.cases.md +22 -0
  51. package/rules/html/img-alt.md +44 -0
  52. package/rules/html/img-title.md +40 -0
  53. package/rules/html/input-attributes.md +34 -0
  54. package/rules/html/input-image-alt.md +39 -0
  55. package/rules/html/input-missing-label.md +40 -0
  56. package/rules/html/link-text.md +39 -0
  57. package/rules/html/long-title.md +40 -0
  58. package/rules/html/map-dup-name.md +40 -0
  59. package/rules/html/map-id-name.md +38 -0
  60. package/rules/html/meta-refresh.md +42 -0
  61. package/rules/html/missing-doctype.cases.md +24 -0
  62. package/rules/html/missing-doctype.md +43 -0
  63. package/rules/html/multiple-labeled-controls.md +40 -0
  64. package/rules/html/no-abstract-role.md +39 -0
  65. package/rules/html/no-autoplay.md +37 -0
  66. package/rules/html/no-conditional-comment.md +39 -0
  67. package/rules/html/no-deprecated-attr.md +39 -0
  68. package/rules/html/no-dup-attr.md +37 -0
  69. package/rules/html/no-dup-class.md +33 -0
  70. package/rules/html/no-duplicate-id.cases.md +23 -0
  71. package/rules/html/no-duplicate-id.md +42 -0
  72. package/rules/html/no-implicit-close.cases.md +38 -0
  73. package/rules/html/no-implicit-close.md +40 -0
  74. package/rules/html/no-implicit-input-type.md +34 -0
  75. package/rules/html/no-inline-script.md +42 -0
  76. package/rules/html/no-inline-style.cases.md +12 -0
  77. package/rules/html/no-inline-style.md +42 -0
  78. package/rules/html/no-missing-references.md +39 -0
  79. package/rules/html/no-multiple-main.md +40 -0
  80. package/rules/html/no-raw-characters.cases.md +84 -0
  81. package/rules/html/no-raw-characters.md +35 -0
  82. package/rules/html/no-redundant-aria-label.md +36 -0
  83. package/rules/html/no-redundant-for.md +34 -0
  84. package/rules/html/no-redundant-role.md +42 -0
  85. package/rules/html/no-utf8-bom.md +45 -0
  86. package/rules/html/prefer-button.md +39 -0
  87. package/rules/html/prefer-native-element.md +40 -0
  88. package/rules/html/prefer-tbody.md +41 -0
  89. package/rules/html/require-sri.md +41 -0
  90. package/rules/html/script-element.md +36 -0
  91. package/rules/html/script-type.md +33 -0
  92. package/rules/html/target-blank-rel.cases.md +35 -0
  93. package/rules/html/target-blank-rel.md +32 -0
  94. package/rules/html/tel-non-breaking.md +37 -0
  95. package/rules/html/text-content.md +39 -0
  96. package/rules/html/th-scope.md +47 -0
  97. package/rules/html/unique-landmark.md +41 -0
  98. package/rules/html/unrecognized-char-ref.cases.md +41 -0
  99. package/rules/html/unrecognized-char-ref.md +42 -0
  100. package/rules/html/valid-autocomplete.cases.md +42 -0
  101. package/rules/html/valid-autocomplete.md +42 -0
  102. package/rules/html/valid-for.md +40 -0
  103. package/rules/html/valid-id.md +40 -0
  104. package/rules/html/void-content.md +34 -0
@@ -0,0 +1,41 @@
1
+ ---
2
+ id: html/require-sri
3
+ title: "Scripts and stylesheets carry an integrity hash"
4
+ languages: [html]
5
+ fix: manual
6
+ fix_reason: "the hash must be computed from the exact file served"
7
+ stability: preview
8
+ options:
9
+ target: { type: "string", default: "all", description: "`all` checks every resource; `crossorigin` only those loaded from another origin" }
10
+ ported_from: [html-validate/require-sri]
11
+ since: 0.1.0
12
+ ---
13
+
14
+ Every `<script src>` and `<link rel="stylesheet">` (and `modulepreload`, and `preload` of a script or style) has an `integrity` attribute.
15
+
16
+ **Why:** Subresource Integrity makes the browser refuse a file that changed on the CDN or in transit.
17
+
18
+ ```codelaw
19
+ native: html/require-sri
20
+ ```
21
+
22
+ ## How to fix
23
+
24
+ 1. Compute the file's hash, for example `openssl dgst -sha384 -binary lib.js | openssl base64 -A`.
25
+ 2. Add `integrity="sha384-…"` and `crossorigin="anonymous"`.
26
+
27
+ ## Examples
28
+
29
+ ### HTML
30
+
31
+ #### Don't
32
+
33
+ ```html
34
+ <script src="https://cdn.example.com/lib.js"></script>
35
+ ```
36
+
37
+ #### Do
38
+
39
+ ```html
40
+ <script src="https://cdn.example.com/lib.js" integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC" crossorigin="anonymous"></script>
41
+ ```
@@ -0,0 +1,36 @@
1
+ ---
2
+ id: html/script-element
3
+ title: "<script> has an end tag"
4
+ languages: [html]
5
+ fix: suggest
6
+ fix_reason: "the markup the open script swallowed starts being rendered"
7
+ stability: preview
8
+ ported_from: [html-validate/script-element]
9
+ since: 0.1.0
10
+ ---
11
+
12
+ A `<script>` is closed with `</script>`, also when it has `src`; `<script … />` is not a closed script.
13
+
14
+ **Why:** HTML ignores the `/>`, so the browser reads everything up to the next `</script>` as script and the content in between disappears.
15
+
16
+ ```codelaw
17
+ native: html/script-element
18
+ ```
19
+
20
+ ## Examples
21
+
22
+ ### HTML
23
+
24
+ #### Don't
25
+
26
+ ```html
27
+ <script src="app.js" />
28
+ <p>Hello</p>
29
+ ```
30
+
31
+ #### Do
32
+
33
+ ```html
34
+ <script src="app.js"></script>
35
+ <p>Hello</p>
36
+ ```
@@ -0,0 +1,33 @@
1
+ ---
2
+ id: html/script-type
3
+ title: "No type on JavaScript scripts"
4
+ languages: [html]
5
+ fix: auto
6
+ stability: preview
7
+ ported_from: [html-validate/script-type]
8
+ since: 0.1.0
9
+ ---
10
+
11
+ A `<script>` doesn't say `type="text/javascript"` or another JavaScript MIME type.
12
+
13
+ **Why:** JavaScript is the default; the attribute adds nothing, and legacy types such as `text/ecmascript` mislead.
14
+
15
+ ```codelaw
16
+ native: html/script-type
17
+ ```
18
+
19
+ ## Examples
20
+
21
+ ### HTML
22
+
23
+ #### Don't
24
+
25
+ ```html
26
+ <script type="text/javascript" src="app.js"></script>
27
+ ```
28
+
29
+ #### Do
30
+
31
+ ```html
32
+ <script src="app.js"></script>
33
+ ```
@@ -0,0 +1,35 @@
1
+ # html/target-blank-rel — cases
2
+
3
+ ### case: noreferrer also prevents the opener
4
+
5
+ ```html
6
+ <a href="/a" target="_blank" rel="noreferrer">a</a>
7
+ ```
8
+
9
+ ```expect
10
+ (none)
11
+ ```
12
+
13
+ ### case: an existing rel gets noopener added
14
+
15
+ ```html
16
+ <a href="/a" target="_blank" rel="external">a</a>
17
+ ```
18
+
19
+ ```expect
20
+ 1:14 html/target-blank-rel
21
+ ```
22
+
23
+ ```fixed
24
+ <a href="/a" target="_blank" rel="external noopener">a</a>
25
+ ```
26
+
27
+ ### case: a link without href opens nothing
28
+
29
+ ```html
30
+ <a target="_blank">a</a>
31
+ ```
32
+
33
+ ```expect
34
+ (none)
35
+ ```
@@ -0,0 +1,32 @@
1
+ ---
2
+ id: html/target-blank-rel
3
+ title: "Links that open a new tab set rel=\"noopener\""
4
+ languages: [html]
5
+ fix: auto
6
+ stability: preview
7
+ since: 0.1.0
8
+ ---
9
+
10
+ An `<a>` or `<area>` with `target="_blank"` and an `href` (or a `<form>` with an `action`) has `rel="noopener"` or `rel="noreferrer"`.
11
+
12
+ **Why:** Without it, older browsers give the opened page a handle on this one (`window.opener`), which it can use to redirect it.
13
+
14
+ ```codelaw
15
+ native: html/target-blank-rel
16
+ ```
17
+
18
+ ## Examples
19
+
20
+ ### HTML
21
+
22
+ #### Don't
23
+
24
+ ```html
25
+ <a href="https://example.com" target="_blank">Example</a>
26
+ ```
27
+
28
+ #### Do
29
+
30
+ ```html
31
+ <a href="https://example.com" target="_blank" rel="noopener">Example</a>
32
+ ```
@@ -0,0 +1,37 @@
1
+ ---
2
+ id: html/tel-non-breaking
3
+ title: "Phone numbers don't wrap"
4
+ languages: [html]
5
+ fix: suggest
6
+ fix_reason: "the text then contains non-breaking characters, which copy and search keep"
7
+ stability: preview
8
+ options:
9
+ ignoreClasses: { type: "string[]", default: [], description: "classes that already prevent wrapping" }
10
+ ignoreStyle: { type: "boolean", default: true, description: "skip links styled `white-space: nowrap` or `pre`" }
11
+ ported_from: [html-validate/tel-non-breaking]
12
+ since: 0.1.0
13
+ ---
14
+
15
+ The text of a `tel:` link uses non-breaking spaces and hyphens.
16
+
17
+ **Why:** A phone number broken over two lines is hard to read and to copy.
18
+
19
+ ```codelaw
20
+ native: html/tel-non-breaking
21
+ ```
22
+
23
+ ## Examples
24
+
25
+ ### HTML
26
+
27
+ #### Don't
28
+
29
+ ```html
30
+ <a href="tel:5551234">555 1234</a>
31
+ ```
32
+
33
+ #### Do
34
+
35
+ ```html
36
+ <a href="tel:5551234">555&nbsp;1234</a>
37
+ ```
@@ -0,0 +1,39 @@
1
+ ---
2
+ id: html/text-content
3
+ title: "Buttons have text"
4
+ languages: [html]
5
+ fix: manual
6
+ fix_reason: "the button's name needs a human"
7
+ stability: preview
8
+ ported_from: [html-validate/text-content]
9
+ tags: [a11y]
10
+ since: 0.1.0
11
+ ---
12
+
13
+ A `<button>` has text a screen reader can announce: content, `aria-label`, `aria-labelledby`, or an image with `alt`.
14
+
15
+ **Why:** Without it the button is announced as just "button".
16
+
17
+ ```codelaw
18
+ native: html/text-content
19
+ ```
20
+
21
+ ## How to fix
22
+
23
+ 1. Add visible text, or an `aria-label` that says what the button does.
24
+
25
+ ## Examples
26
+
27
+ ### HTML
28
+
29
+ #### Don't
30
+
31
+ ```html
32
+ <button type="button"><svg width="16" height="16"></svg></button>
33
+ ```
34
+
35
+ #### Do
36
+
37
+ ```html
38
+ <button type="button" aria-label="Close"><svg width="16" height="16"></svg></button>
39
+ ```
@@ -0,0 +1,47 @@
1
+ ---
2
+ id: html/th-scope
3
+ title: "Header cells in complex tables have scope"
4
+ languages: [html]
5
+ fix: manual
6
+ fix_reason: "whether each header labels a row or a column is the author's call"
7
+ stability: preview
8
+ options:
9
+ strict: { type: "boolean", default: false, description: "check simple tables too" }
10
+ ported_from: [html-validate/wcag/h63]
11
+ tags: [a11y]
12
+ since: 0.1.0
13
+ ---
14
+
15
+ In a table whose headers are not just the first row or just the first column, every `<th>` has `scope` (`row`, `col`, `rowgroup` or `colgroup`).
16
+
17
+ **Why:** Screen readers announce each cell with its headers; `scope` tells them which headers belong to which cells.
18
+
19
+ ```codelaw
20
+ native: html/th-scope
21
+ ```
22
+
23
+ ## How to fix
24
+
25
+ 1. Add `scope="col"` to column headers and `scope="row"` to row headers.
26
+
27
+ ## Examples
28
+
29
+ ### HTML
30
+
31
+ #### Don't
32
+
33
+ ```html
34
+ <table>
35
+ <tr><th>Name</th><th>Age</th></tr>
36
+ <tr><th>Ada</th><td>36</td></tr>
37
+ </table>
38
+ ```
39
+
40
+ #### Do
41
+
42
+ ```html
43
+ <table>
44
+ <tr><th scope="col">Name</th><th scope="col">Age</th></tr>
45
+ <tr><th scope="row">Ada</th><td>36</td></tr>
46
+ </table>
47
+ ```
@@ -0,0 +1,41 @@
1
+ ---
2
+ id: html/unique-landmark
3
+ title: "Repeated landmarks have distinct names"
4
+ languages: [html]
5
+ fix: manual
6
+ fix_reason: "the names need a human"
7
+ stability: preview
8
+ ported_from: [html-validate/unique-landmark]
9
+ tags: [a11y]
10
+ since: 0.1.0
11
+ ---
12
+
13
+ When a landmark appears more than once (two `<nav>`, two `<aside>`, …), each has a unique, non-empty `aria-label` or `aria-labelledby`.
14
+
15
+ **Why:** Screen-reader users jump between landmarks by name; two unnamed `<nav>` are indistinguishable.
16
+
17
+ ```codelaw
18
+ native: html/unique-landmark
19
+ ```
20
+
21
+ ## How to fix
22
+
23
+ 1. Give each landmark of the same kind its own `aria-label`, or point `aria-labelledby` at its heading.
24
+
25
+ ## Examples
26
+
27
+ ### HTML
28
+
29
+ #### Don't
30
+
31
+ ```html
32
+ <nav><a href="/">Home</a></nav>
33
+ <nav><a href="/help">Help</a></nav>
34
+ ```
35
+
36
+ #### Do
37
+
38
+ ```html
39
+ <nav aria-label="Main"><a href="/">Home</a></nav>
40
+ <nav aria-label="Footer"><a href="/help">Help</a></nav>
41
+ ```
@@ -0,0 +1,41 @@
1
+ # html/unrecognized-char-ref — cases
2
+
3
+ ### case: numeric references are not looked up
4
+
5
+ ```html
6
+ <p>&#169; &#xA9;</p>
7
+ ```
8
+
9
+ ```expect
10
+ (none)
11
+ ```
12
+
13
+ ### case: query strings in URLs may hold unterminated names
14
+
15
+ ```html
16
+ <a href="/s?q=1&copy=2">x</a>
17
+ ```
18
+
19
+ ```expect
20
+ (none)
21
+ ```
22
+
23
+ ### case: a legacy name without its semicolon
24
+
25
+ ```html
26
+ <p>&copy 2024</p>
27
+ ```
28
+
29
+ ```expect
30
+ 1:4 html/unrecognized-char-ref
31
+ ```
32
+
33
+ ### case: an unknown name
34
+
35
+ ```html
36
+ <p>&nbps;</p>
37
+ ```
38
+
39
+ ```expect
40
+ 1:4 html/unrecognized-char-ref
41
+ ```
@@ -0,0 +1,42 @@
1
+ ---
2
+ id: html/unrecognized-char-ref
3
+ title: "Character references exist and are terminated"
4
+ languages: [html]
5
+ fix: manual
6
+ fix_reason: "the intended character is not always clear"
7
+ stability: preview
8
+ options:
9
+ ignoreCase: { type: "boolean", default: false, description: "compare names without case" }
10
+ requireSemicolon: { type: "boolean", default: true, description: "report references without `;`" }
11
+ ported_from: [html-validate/unrecognized-char-ref]
12
+ since: 0.1.0
13
+ ---
14
+
15
+ Every named character reference (`&name;`) is one HTML defines, and ends with `;`.
16
+
17
+ **Why:** An unknown reference is shown literally, and an unterminated one may be read with the text after it.
18
+
19
+ ```codelaw
20
+ native: html/unrecognized-char-ref
21
+ ```
22
+
23
+ ## How to fix
24
+
25
+ 1. Correct the name, or escape the `&` as `&amp;` if no reference was meant.
26
+ 2. End the reference with `;`.
27
+
28
+ ## Examples
29
+
30
+ ### HTML
31
+
32
+ #### Don't
33
+
34
+ ```html
35
+ <p>Price: 5&euros; &copy 2024</p>
36
+ ```
37
+
38
+ #### Do
39
+
40
+ ```html
41
+ <p>Price: 5&euro; &copy; 2024</p>
42
+ ```
@@ -0,0 +1,42 @@
1
+ # html/valid-autocomplete — cases
2
+
3
+ ### case: a section and a hint before the field
4
+
5
+ ```html
6
+ <input type="text" name="a" autocomplete="section-ship shipping address-line1">
7
+ ```
8
+
9
+ ```expect
10
+ (none)
11
+ ```
12
+
13
+ ### case: a multi-line field belongs on a textarea
14
+
15
+ ```html
16
+ <input type="text" name="a" autocomplete="street-address">
17
+ <textarea name="b" autocomplete="street-address"></textarea>
18
+ ```
19
+
20
+ ```expect
21
+ 1:43 html/valid-autocomplete
22
+ ```
23
+
24
+ ### case: on and off are not combined with fields
25
+
26
+ ```html
27
+ <input type="text" name="a" autocomplete="off">
28
+ ```
29
+
30
+ ```expect
31
+ (none)
32
+ ```
33
+
34
+ ### case: form takes only on or off
35
+
36
+ ```html
37
+ <form autocomplete="email"></form>
38
+ ```
39
+
40
+ ```expect
41
+ 1:21 html/valid-autocomplete
42
+ ```
@@ -0,0 +1,42 @@
1
+ ---
2
+ id: html/valid-autocomplete
3
+ title: "autocomplete values are valid"
4
+ languages: [html]
5
+ fix: manual
6
+ fix_reason: "the right field name depends on what the field collects"
7
+ stability: preview
8
+ ported_from: [html-validate/valid-autocomplete]
9
+ tags: [a11y]
10
+ since: 0.1.0
11
+ ---
12
+
13
+ `autocomplete` holds a valid token list: optional `section-*`, then `shipping`/`billing`, then `home`/`work`/… for contact fields, then one field name that fits the input type, then optional `webauthn`. `<form>` takes only `on` or `off`.
14
+
15
+ **Why:** Browsers ignore an invalid value, so autofill and password managers can't help the user.
16
+
17
+ ```codelaw
18
+ native: html/valid-autocomplete
19
+ ```
20
+
21
+ ## How to fix
22
+
23
+ 1. Pick the field name that describes the data (the WHATWG autofill list).
24
+ 2. Order the tokens as described above, or use `off`.
25
+
26
+ ## Examples
27
+
28
+ ### HTML
29
+
30
+ #### Don't
31
+
32
+ ```html
33
+ <input type="email" name="email" autocomplete="mail">
34
+ <input type="number" name="n" autocomplete="email">
35
+ ```
36
+
37
+ #### Do
38
+
39
+ ```html
40
+ <input type="email" name="email" autocomplete="email">
41
+ <input type="number" name="n" autocomplete="off">
42
+ ```
@@ -0,0 +1,40 @@
1
+ ---
2
+ id: html/valid-for
3
+ title: "A label points at a control"
4
+ languages: [html]
5
+ fix: manual
6
+ fix_reason: "either the id or the element is wrong, and only the author knows which"
7
+ stability: preview
8
+ ported_from: [html-validate/valid-for]
9
+ since: 0.1.0
10
+ ---
11
+
12
+ A `<label for>` refers to the id of a form control a label can name (`input`, `select`, `textarea`, `button`, `meter`, `output`, `progress`).
13
+
14
+ **Why:** Pointed at a `<div>` or `<span>`, the label names nothing, and clicking it does nothing.
15
+
16
+ ```codelaw
17
+ native: html/valid-for
18
+ ```
19
+
20
+ ## How to fix
21
+
22
+ 1. Point `for` at the control's id, or make the target a form control.
23
+
24
+ ## Examples
25
+
26
+ ### HTML
27
+
28
+ #### Don't
29
+
30
+ ```html
31
+ <label for="name">Name</label>
32
+ <div id="name"></div>
33
+ ```
34
+
35
+ #### Do
36
+
37
+ ```html
38
+ <label for="name">Name</label>
39
+ <input type="text" id="name">
40
+ ```
@@ -0,0 +1,40 @@
1
+ ---
2
+ id: html/valid-id
3
+ title: "Ids are well-formed"
4
+ languages: [html]
5
+ fix: manual
6
+ fix_reason: "renaming an id breaks the CSS, scripts and links that use it"
7
+ stability: preview
8
+ options:
9
+ relaxed: { type: "boolean", default: false, description: "only require a non-empty id without whitespace" }
10
+ ported_from: [html-validate/valid-id]
11
+ since: 0.1.0
12
+ ---
13
+
14
+ An `id` is not empty and has no whitespace; it starts with a letter and uses only letters, digits, `-` and `_`.
15
+
16
+ **Why:** Whitespace makes the id unusable; other characters need escaping in CSS selectors and are easy to get wrong.
17
+
18
+ ```codelaw
19
+ native: html/valid-id
20
+ ```
21
+
22
+ ## How to fix
23
+
24
+ 1. Rename the id, and update everything that refers to it.
25
+
26
+ ## Examples
27
+
28
+ ### HTML
29
+
30
+ #### Don't
31
+
32
+ ```html
33
+ <div id="1st item"></div>
34
+ ```
35
+
36
+ #### Do
37
+
38
+ ```html
39
+ <div id="first-item"></div>
40
+ ```
@@ -0,0 +1,34 @@
1
+ ---
2
+ id: html/void-content
3
+ title: "Void elements have no end tag"
4
+ languages: [html]
5
+ fix: suggest
6
+ fix_reason: "`</br>` is read as a second line break, so removing it changes the rendering"
7
+ stability: preview
8
+ ported_from: [html-validate/void-content]
9
+ since: 0.1.0
10
+ ---
11
+
12
+ Void elements (`<br>`, `<img>`, `<input>`, `<meta>`, …) are written without an end tag.
13
+
14
+ **Why:** They can't have content; browsers ignore most such end tags, and read `</br>` and `</p>` as new elements.
15
+
16
+ ```codelaw
17
+ native: html/void-content
18
+ ```
19
+
20
+ ## Examples
21
+
22
+ ### HTML
23
+
24
+ #### Don't
25
+
26
+ ```html
27
+ <input type="text" name="q"></input>
28
+ ```
29
+
30
+ #### Do
31
+
32
+ ```html
33
+ <input type="text" name="q">
34
+ ```