diff --git a/.changeset/html-comment-in-open-tag.md b/.changeset/html-comment-in-open-tag.md
new file mode 100644
index 00000000..13c92d7e
--- /dev/null
+++ b/.changeset/html-comment-in-open-tag.md
@@ -0,0 +1,5 @@
+---
+"htmljs-parser": minor
+---
+
+An ` id="b">` reports the comment rather than silently parsing as `class=("a" < !--note)` plus two junk attributes.
diff --git a/src/__tests__/fixtures/attr-value-html-comment-in-regex/__snapshots__/attr-value-html-comment-in-regex.expected.txt b/src/__tests__/fixtures/attr-value-html-comment-in-regex/__snapshots__/attr-value-html-comment-in-regex.expected.txt
new file mode 100644
index 00000000..2a977d45
--- /dev/null
+++ b/src/__tests__/fixtures/attr-value-html-comment-in-regex/__snapshots__/attr-value-html-comment-in-regex.expected.txt
@@ -0,0 +1,10 @@
+1╭─
+ │ ││ │ ││ │ ││ ╰─ openTagEnd:selfClosed "/>"
+ │ ││ │ ││ │ │╰─ attrValue.value "\"\""
+ │ ││ │ ││ │ ╰─ attrValue "=\"\""
+ │ ││ │ ││ ╰─ attrName "title"
+ │ ││ │ │╰─ attrValue.value "/"/>
\ No newline at end of file
diff --git a/src/__tests__/fixtures/invalid-html-comment-after-attr-name/__snapshots__/invalid-html-comment-after-attr-name.expected.txt b/src/__tests__/fixtures/invalid-html-comment-after-attr-name/__snapshots__/invalid-html-comment-after-attr-name.expected.txt
new file mode 100644
index 00000000..f617788b
--- /dev/null
+++ b/src/__tests__/fixtures/invalid-html-comment-after-attr-name/__snapshots__/invalid-html-comment-after-attr-name.expected.txt
@@ -0,0 +1,5 @@
+1╭─ id="b">hi
+ │ ││ │ ╰─ error(INVALID_HTML_COMMENT:An html comment cannot be used within an open tag. Use a JavaScript comment (// or /* */) instead.)
+ │ ││ ╰─ attrName "hidden"
+ │ │╰─ tagName "div"
+ ╰─ ╰─ openTagStart
\ No newline at end of file
diff --git a/src/__tests__/fixtures/invalid-html-comment-after-attr-name/input.marko b/src/__tests__/fixtures/invalid-html-comment-after-attr-name/input.marko
new file mode 100644
index 00000000..acea281d
--- /dev/null
+++ b/src/__tests__/fixtures/invalid-html-comment-after-attr-name/input.marko
@@ -0,0 +1 @@
+ id="b">hi
\ No newline at end of file
diff --git a/src/__tests__/fixtures/invalid-html-comment-after-attr-value/__snapshots__/invalid-html-comment-after-attr-value.expected.txt b/src/__tests__/fixtures/invalid-html-comment-after-attr-value/__snapshots__/invalid-html-comment-after-attr-value.expected.txt
new file mode 100644
index 00000000..19071aa3
--- /dev/null
+++ b/src/__tests__/fixtures/invalid-html-comment-after-attr-value/__snapshots__/invalid-html-comment-after-attr-value.expected.txt
@@ -0,0 +1,7 @@
+1╭─ id="b">hi
+ │ ││ │ ││ ╰─ error(INVALID_HTML_COMMENT:An html comment cannot be used within an open tag. Use a JavaScript comment (// or /* */) instead.)
+ │ ││ │ │╰─ attrValue.value "\"foo\""
+ │ ││ │ ╰─ attrValue "=\"foo\""
+ │ ││ ╰─ attrName "class"
+ │ │╰─ tagName "div"
+ ╰─ ╰─ openTagStart
\ No newline at end of file
diff --git a/src/__tests__/fixtures/invalid-html-comment-after-attr-value/input.marko b/src/__tests__/fixtures/invalid-html-comment-after-attr-value/input.marko
new file mode 100644
index 00000000..0e2e82f8
--- /dev/null
+++ b/src/__tests__/fixtures/invalid-html-comment-after-attr-value/input.marko
@@ -0,0 +1 @@
+ id="b">hi
\ No newline at end of file
diff --git a/src/__tests__/fixtures/invalid-html-comment-concise/__snapshots__/invalid-html-comment-concise.expected.txt b/src/__tests__/fixtures/invalid-html-comment-concise/__snapshots__/invalid-html-comment-concise.expected.txt
new file mode 100644
index 00000000..475ceb38
--- /dev/null
+++ b/src/__tests__/fixtures/invalid-html-comment-concise/__snapshots__/invalid-html-comment-concise.expected.txt
@@ -0,0 +1,6 @@
+1╭─ div class="foo" id="b"
+ │ │ │ ││ ╰─ error(INVALID_HTML_COMMENT:An html comment cannot be used within an open tag. Use a JavaScript comment (// or /* */) instead.)
+ │ │ │ │╰─ attrValue.value "\"foo\""
+ │ │ │ ╰─ attrValue "=\"foo\""
+ │ │ ╰─ attrName "class"
+ ╰─ ╰─ tagName "div"
\ No newline at end of file
diff --git a/src/__tests__/fixtures/invalid-html-comment-concise/input.marko b/src/__tests__/fixtures/invalid-html-comment-concise/input.marko
new file mode 100644
index 00000000..103ee554
--- /dev/null
+++ b/src/__tests__/fixtures/invalid-html-comment-concise/input.marko
@@ -0,0 +1 @@
+div class="foo" id="b"
\ No newline at end of file
diff --git a/src/__tests__/fixtures/invalid-html-comment-in-open-tag/__snapshots__/invalid-html-comment-in-open-tag.expected.txt b/src/__tests__/fixtures/invalid-html-comment-in-open-tag/__snapshots__/invalid-html-comment-in-open-tag.expected.txt
new file mode 100644
index 00000000..27144e88
--- /dev/null
+++ b/src/__tests__/fixtures/invalid-html-comment-in-open-tag/__snapshots__/invalid-html-comment-in-open-tag.expected.txt
@@ -0,0 +1,7 @@
+1╭─
+ ╰─ ╰─ error(INVALID_HTML_COMMENT:An html comment cannot be used within an open tag. Use a JavaScript comment (// or /* */) instead.)
+3├─ class="foo"
+4╰─ >hi
\ No newline at end of file
diff --git a/src/__tests__/fixtures/invalid-html-comment-in-open-tag/input.marko b/src/__tests__/fixtures/invalid-html-comment-in-open-tag/input.marko
new file mode 100644
index 00000000..1751484a
--- /dev/null
+++ b/src/__tests__/fixtures/invalid-html-comment-in-open-tag/input.marko
@@ -0,0 +1,4 @@
+
+ class="foo"
+>hi
\ No newline at end of file
diff --git a/src/states/ATTRIBUTE.ts b/src/states/ATTRIBUTE.ts
index 16dd3e74..e7d801fe 100644
--- a/src/states/ATTRIBUTE.ts
+++ b/src/states/ATTRIBUTE.ts
@@ -83,6 +83,11 @@ export const ATTRIBUTE: StateDefinition = {
continue;
}
+ if (code === CODE.OPEN_ANGLE_BRACKET && this.lookAheadFor("!--")) {
+ this.exitState();
+ return; // the open tag reports the html comment
+ }
+
if (
code === CODE.EQUAL ||
(code === CODE.COLON && data.charCodeAt(this.pos + 1) === CODE.EQUAL) ||
diff --git a/src/states/EXPRESSION.ts b/src/states/EXPRESSION.ts
index f4dc7f26..2f9fd156 100644
--- a/src/states/EXPRESSION.ts
+++ b/src/states/EXPRESSION.ts
@@ -420,14 +420,20 @@ function checkForOperators(
pos + 1,
);
- // In HTML mode a "" is a close tag rather than a less-than operator
- // (which lookAheadForOperator would otherwise continue across).
- if (
- !parser.isConcise &&
- data.charCodeAt(nextNonSpace) === CODE.OPEN_ANGLE_BRACKET &&
- data.charCodeAt(nextNonSpace + 1) === CODE.FORWARD_SLASH
- ) {
- return false;
+ // A "" close tag (html mode) or a "