Stop stripping HTML with regex: the browser already knows the plain text
Every developer has written this line at some point: const text = html.replace(/<[^>]*>/g, ""); It looks reasonable. It passes the first test. Then it meets real HTML and falls apart in five different ways at on
Every developer has written this line at some point:
const text = html.replace(/<[^>]*>/g, "");
It looks reasonable. It passes the first test. Then it meets real HTML and falls apart in five different ways at once.
The problem is not your regex. The problem is that HTML is not a regular language, and no pattern can understand it the way a parser can.
Where the regex breaks
Take a simple email template:
<p>Hi Ana,</p>
<p>Your order <strong>#4821</strong> ships on <time>Friday</time>.</p>
<ul>
<li>Tracking link inside your account</li>
<li>Free returns for 30 days</li>
</ul>
Strip the tags with a regex and you get:
Hi Ana,Your order #4821 ships on Friday.Tracking link inside your accountFree returns for 30 days
Every paragraph boundary is gone. The list items run together. The text is technically tag-free and completely unreadable. A regex sees characters, not structure. It cannot know that </p> means "new paragraph" or that <li> means "new line with a bullet".
Then there are the cases where it silently corrupts content. A <script> block full of comparison operators becomes text. A > inside an attribute value (<a title="a > b">) ends the "tag" early and leaves markup in your output. An HTML entity like & stays as the literal characters & instead of becoming &. And becomes a non-breaking space that looks identical to a normal space but breaks every search, split and comparison you run on the result afterwards.
The browser already solved this
Here is the thing most people miss: you do not need a library to extract text from HTML correctly. The browser ships with a real HTML parser, and it is one function call away.
const doc = new DOMParser().parseFromString(html, "text/html");
const text = doc.body.innerText;
DOMParser builds a real document from your markup. It is inert: scripts never run, images and stylesheets never load, nothing is fetched. Then innerText walks that document the way a browser renders it: block elements get line breaks, paragraphs get blank lines between them, <br> becomes a newline, list items get their markers, table cells get separated. The parser handles the entities, the malformed nesting, the unclosed tags. All the edge cases your regex was about to meet have already been handled, by the same engine that renders every web page you have ever opened.
There are two details worth knowing. First, innerText is aware of what is visible, so content inside <script> and <style> is excluded, while textContent would include it. If you want the readable text of a page, innerText is the one you want. Second, this runs entirely in the browser. Nothing is uploaded, which matters when the HTML you are cleaning is a client email template or a page full of internal links.
The options that make the output actually usable
A raw text dump is only half the job. Three small choices turn it into text you can paste somewhere and trust:
Keep the link destinations. A link that reads "read the docs" is useless in plain text unless the URL survives. Writing it as read the docs (https://example.com/docs) keeps the destination attached to the words.
Keep image alt text. In plain text, an image is invisible, but its alt text is often the only description of what was there. Writing it as [Product photo: blue running shoes] preserves the information instead of silently dropping it.
Keep the list structure. Bullets and numbers are not decoration. They tell the reader where one item ends and the next begins, and without them a five-item list becomes one long sentence.
Tables deserve the same treatment. A row of cells joined with tabs keeps the columns readable, while cells joined with nothing turn "Price 49.99" into "Price49.99".
When you actually need this
This comes up more often than people expect. Cleaning up HTML email templates before pasting them into a plain-text field. Pulling the readable text out of a saved web page for a search index. Turning a Word export full of markup into something you can paste into a form. Preparing page content for an LLM prompt, where every stray tag is wasted tokens. Checking what a screen reader or a search engine actually sees when the styling is gone.
In every one of those cases, the goal is the same: the words, in the right order, with the structure a human reader needs and nothing else.
I built a free HTML to text converter that does exactly this, using the browser parser approach above. It keeps paragraphs, lists and tables readable, decodes entities properly, strips scripts and styles, and lets you choose whether link URLs and image alt text survive. It also takes a file upload and gives you a clean .txt download. It runs entirely in your browser, and you can try it here: HTML to Text Converter.
Your HTML is not text with angle brackets sprinkled on it. It is a document. Let a parser read it.
Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.