How to get text from an HTML string in JavaScript?
Strip the tags from an HTML string and get plain text with DOMParser, why innerHTML on a div is unsafe, and when a regex is good enough.
Parse the string with DOMParser and read textContent of the document body. The browser does the parsing, decodes entities like &, and nothing inside the string runs.
const html = '<a href="/x">Read more</a>';
const doc = new DOMParser().parseFromString(html, 'text/html');
const text = doc.body.textContent;
console.log(text); // "Read more"This is safe for strings you don't control, such as CMS content or API responses. A document created by DOMParser is inert: scripts don't run, event handlers don't fire, and images don't load.
The parsed document works like any other, so you can also pick out a single element:
const doc = new DOMParser().parseFromString(html, 'text/html');
const link = doc.querySelector('a');
link.textContent; // "Read more"
link.getAttribute('href'); // "/x"Two things textContent doesn't do for you
textContent joins text nodes without adding spaces or line breaks, so <p>One</p><p>Two</p> becomes "OneTwo". If the words must stay apart, read the block elements one by one and join them yourself.
It also includes the contents of <style> and <script> elements. Remove them first if the string can contain them:
const doc = new DOMParser().parseFromString(html, 'text/html');
doc.querySelectorAll('script, style').forEach((el) => el.remove());
const text = doc.body.textContent;Don't use innerHTML on a temporary div
You'll often see this trick:
// Don't do this with strings you don't control
const div = document.createElement('div');
div.innerHTML = '<img src="x" onerror="alert(1)">';
const text = div.textContent;The div is never added to the page, but the onerror handler still runs. The browser creates a real <img> element, starts loading x, fails, and fires the handler. With user content, that's an XSS hole. DOMParser gives you the same result without the risk.
Regex: fine for simple, trusted strings
For a short string you wrote yourself, a regex that removes everything between < and > does the job:
const strip = (html) => html.replace(/<[^>]*>/g, '');
strip('<a href="/x">Read more</a>'); // "Read more"It breaks as soon as the HTML gets less tidy:
strip('<p>Fish & chips</p>'); // "Fish & chips"
strip('<a title="a > b">Link</a>'); // ' b">Link'
strip('<!-- a > b -->Hello'); // " b -->Hello"
strip('<p>1 < 2</p>'); // "1 "It doesn't decode entities, it stops at the first > even inside an attribute or a comment, and a lone < in the text swallows everything up to the next tag. The output isn't sanitized either, so never insert it back into the page with innerHTML.
In Node.js
Node.js has no DOMParser. Use a library such as node-html-parser or cheerio:
import { parse } from 'node-html-parser';
parse('<p>Fish & chips</p>').textContent; // "Fish & chips"import * as cheerio from 'cheerio';
const $ = cheerio.load('<a href="/x">Read more</a>');
$('a').text(); // "Read more"Both decode entities. Pick cheerio if you also need to query and change the markup with a jQuery-like API, and node-html-parser if you mostly need the text and want a lighter dependency.