Quick answer
To find HTML tags, use <\/?([A-Za-z][A-Za-z0-9-]*)(?:\s[^>]*)?\/?> with the g flag. It matches opening, closing and self-closing tags such as <div class="card">, </div> and <br/>, and captures the tag name in group 1. It is fine for quick text cleanup, but use DOMParser or an HTML sanitizer for anything involving untrusted HTML.
- Tested examples
- Token-by-token breakdown
- Code in 5 languages
- Live tester
How to use the HTML tag regex
- 1Copy the pattern with Copy pattern in the tester, or take a snippet for your language from the code section below.
- 2Look at the sample in Test string: every HTML tag the regex finds is highlighted.
- 3Paste your own text to see the matches, then switch to Replace to preview a replacement.
- 4Open the Code tab for JavaScript, Python, Go, C#, PHP or Dart with the pattern translated and escaped.
How does the HTML tag regex work?
Read it left to right. Each piece below matches one part of the input:
<The opening angle bracket.\/?An optional slash, for closing tags like </p>.([A-Za-z][A-Za-z0-9-]*)Group 1, the tag name: a letter, then letters, digits or hyphens (custom elements like my-card).(?:\s[^>]*)?Optionally whitespace and then attributes: anything up to the next >.\/?An optional slash for self-closing syntax like <br/>.>The closing angle bracket.
Flags: g (global).
Which strings does the HTML tag regex match?
The pattern searches inside the text, so a match can be part of a longer string. Every row below is checked against the pattern by our automated test suite before each release.
| Input | Finds a match? | Why |
|---|---|---|
<div> | Yes | A plain opening tag. |
</div> | Yes | A closing tag. |
<a href="https://example.com"> | Yes | Attributes are matched as part of the tag. |
<img src="a.png" alt="" /> | Yes | Self-closing with a space before the slash. |
<my-card data-id="7"> | Yes | Custom element names contain hyphens. |
< div> | No | A space after < means it is not a tag. |
<> | No | No tag name. |
<123> | No | Tag names start with a letter. |
<!-- comment --> | No | Comments are not tags. |
5 < 6 and 7 > 3 | No | Comparison operators in text are left alone. |
Why should you not parse HTML with regex?
HTML is not a regular language: elements nest to any depth, attribute values can contain >, and browsers repair broken markup in specific, documented ways. A regex sees characters, not structure, so it fails on input like:
<a title="x > y">— the>inside the attribute ends the match early.<script>if (a<b) …</script>— script content is not markup.<div\nclass="x">— attributes split across lines (this pattern handles that, many do not).
For reading HTML, let the browser parse it:
const doc = new DOMParser().parseFromString(html, "text/html");
const links = [...doc.querySelectorAll("a[href]")].map((a) => a.href);For untrusted HTML, never strip tags with regex as a security measure: use a sanitizer such as DOMPurify, which is maintained against real XSS bypasses.
How do I strip all tags from a string?
For trusted text where you just want the words, replace every match with nothing:
const text = html.replace(/<\/?([A-Za-z][A-Za-z0-9-]*)(?:\s[^>]*)?\/?>/g, "");Then decode entities (& → &) with a textarea element or a library. In the browser, new DOMParser().parseFromString(html, "text/html").body.textContent does both jobs correctly in one line, including comments and scripts, so prefer it whenever a DOM is available.
How do I use the HTML tag regex in JavaScript, Python, Go, C# and PHP?
The pattern is translated for each engine rather than pasted as is: named groups, anchors, escapes, shorthand classes and flags are adjusted so each snippet behaves as closely to the JavaScript version as its engine allows. Differences that remain (Go's RE2 has no lookarounds or backreferences, for example) are called out under each one. The Code tab in the tester above also exports Dart, and updates as you edit the pattern.
JavaScript and TypeScript
const regex = /<\/?([A-Za-z][A-Za-z0-9-]*)(?:\s[^>]*)?\/?>/g;
const text = "<div>";
for (const match of text.matchAll(regex)) {
console.log(match[0], "at index", match.index);
console.log(match[1]);
}Python
import re
pattern = re.compile(r"<\/?([A-Za-z][A-Za-z0-9\-]*)(?:\s[^>]*)?\/?>")
text = "<div>"
for match in pattern.finditer(text):
print(match.group(0), "at index", match.start())
print(match.groups())Go
package main
import (
"fmt"
"regexp"
)
func main() {
re := regexp.MustCompile(`<\/?([A-Za-z][A-Za-z0-9\-]*)(?:\s[^>]*)?\/?>`)
text := "<div>"
for _, m := range re.FindAllStringSubmatch(text, -1) {
fmt.Println(m[0])
fmt.Println(m[1:])
}
}- Go's \s only matches space, \t, \n, \f and \r; JavaScript's also matches the non-breaking space and other Unicode spaces.
C#
using System;
using System.Text.RegularExpressions;
// The timeout stops a pathological input from hanging the thread (ReDoS).
var regex = new Regex(@"<\/?([A-Za-z][A-Za-z0-9\-]*)(?:\s[^>]*)?\/?>", RegexOptions.None, TimeSpan.FromSeconds(1));
var text = "<div>";
foreach (Match match in regex.Matches(text))
{
Console.WriteLine($"{match.Value} at index {match.Index}");
Console.WriteLine(match.Groups[1].Value);
}PHP
<?php
$pattern = '/<\/?([A-Za-z][A-Za-z0-9\-]*)(?:\s[^>]*)?\/?>/';
$text = '<div>';
preg_match_all($pattern, $text, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE);
foreach ($matches as $match) {
echo $match[0][0], " at index ", $match[0][1], PHP_EOL;
echo $match[1][0], PHP_EOL;
}- PCRE's \s matches ASCII whitespace unless Unicode properties (UCP) are on; JavaScript's also matches the non-breaking space and other Unicode spaces.
Which related regex patterns are useful?
- Regex for URL Validation: http and https links with a real domain, optional port, path, query and fragment.
- Regex to Trim Leading and Trailing Whitespace: Whitespace at the start or end of a string, for trimming with replace().
- Regex for Hex Color Codes: CSS hex colors in 3, 4, 6 or 8 digits with a leading hash.
- Regex for YouTube URLs and Video IDs: Every common YouTube link format, with the 11-character video ID in a named group.
Browse all 25 patterns in the regex pattern library, or build your own in the regex tester.
Frequently asked questions
Last updated by the Playxoft engineering team.