HTML Comment Regex
Detects an HTML comment, <!-- ... -->, using a lazy quantifier so the match stops at the first closing --> instead of swallowing everything up to the last one in the document.
Regex Pattern
<!--[\s\S]*?-->Pattern Breakdown
Hover over a token to see what it does.
| Token | Meaning |
|---|---|
| <!-- | The literal opening delimiter of an HTML comment |
| [\s\S] | A character class matching absolutely any character, including newlines (since plain . cannot match line breaks) |
| *? | A lazy quantifier: match as few characters as possible while still allowing the rest of the pattern to succeed |
| --> | The literal closing delimiter that ends the comment |
Detailed Explanation
What it does
This pattern finds an HTML comment anywhere in a string, from <!-- to the nearest following -->, and correctly handles comments that span multiple lines because [\s\S] matches newlines as well as any other character.
Why it works
[\s\S]*? is the classic 'match anything, lazily' idiom in JavaScript regex, used because the dot metacharacter never matches line-break characters unless the /s (dotAll) flag is set. Making the quantifier lazy (*? instead of *) is essential: with a greedy *, the engine would first try to consume all remaining characters in the string, then backtrack until it finds the LAST --> in the input, potentially swallowing several separate comments (and the real markup between them) into a single incorrect match. The lazy form instead stops at the first --> it encounters, correctly isolating one comment at a time.
Common use cases
- Stripping HTML comments out of a template or generated markup string before rendering
- Extracting documentation or metadata embedded in HTML comments (e.g. <!-- TODO: ... -->)
- Validating that a snippet of markup contains a properly closed comment before saving it
- Building a simple HTML sanitizer or minifier step that removes comment nodes
Edge cases
- A comment spanning multiple lines, like <!-- line one\nline two -->, matches correctly because [\s\S] includes \n
- An empty comment, <!---->, still matches since *? allows zero characters between the delimiters
- An unterminated comment with no closing -->, like <!-- oops, correctly fails to match anything
- With the global flag and .match()/.exec(), two separate comments in one string, <!--a--><!--b-->, are correctly returned as two distinct matches only because the quantifier is lazy; a greedy version would incorrectly merge them into a single match spanning both
Limitations
- Does not validate the HTML spec's restriction that comment content must not start with '>', '->' or contain '--' or end with '-'
- Does not distinguish a comment that appears inside a <script> or <textarea> block, where '<!--' has different parsing rules
- Regex-based comment stripping is not a substitute for a real HTML parser when handling untrusted or malformed markup
Interactive Tester
Edit the pattern or text below — matching runs live in your browser.
Test Cases
Editable — add your own inputs to see if they pass.
| Input | Expected | Result | |
|---|---|---|---|
| Pass | |||
| Pass | |||
| Pass | |||
| Pass | |||
| Pass | |||
| Pass | |||
| Pass | |||
| Pass |
Language Variants
Production-ready examples in 12 languages.
const htmlCommentRegex = /<!--[\s\S]*?-->/;
console.log(htmlCommentRegex.test('<!-- note -->')); // true
// Strip all comments (lazy quantifier keeps each match isolated)
const stripped = '<!--a--><p>x</p><!--b-->'.replace(/<!--[\s\S]*?-->/g, '');Common Mistakes
Using a greedy quantifier, <!--[\s\S]*-->, which spans from the first <!-- all the way to the LAST --> in the document, merging multiple separate comments (and the markup between them) into one match
Fix: Use the lazy quantifier *? so the match stops at the nearest closing --> instead of the farthest one
Using . instead of [\s\S] and forgetting that . does not match newline characters by default, causing multi-line comments to fail
Fix: Use [\s\S] (or enable the /s dotAll flag with . in engines that support it) so the match spans line breaks
Relying on this regex to safely sanitize untrusted HTML for security purposes
Fix: Use a proper HTML parser/sanitizer library for untrusted input; regex-based stripping can be bypassed by malformed or adversarial markup
Performance Notes
- The lazy *? quantifier can require more backtracking steps than a greedy * on pathological inputs with many partial '--' sequences, but stays linear for typical HTML
- Prefer the global flag with matchAll()/exec() loops rather than manually scanning indices when extracting many comments from a large document
- For very large documents, a streaming HTML parser will outperform and outscale a single big regex pass
Browser Compatibility
| Engine | Supported | Notes |
|---|---|---|
| Chrome | Yes | — |
| Firefox | Yes | — |
| Safari | Yes | — |
| Edge | Yes | — |
| Node.js | Yes | — |