Inspect the fixed example
The fixed input includes <strong> and </strong>. Write it using textContent; the literal tags should remain visible.
<style>html{font-size:16px}body{margin:12px;font:1rem/1.5 system-ui,sans-serif;color:#17332d;background:#fff}p{overflow-wrap:anywhere}output{display:block;margin-block:12px;overflow-wrap:anywhere;white-space:pre-wrap}button,input{font:inherit;max-width:100%;box-sizing:border-box}button{margin:4px;padding:8px}label{display:block;margin-block:8px}button:focus-visible,input:focus-visible{outline:3px solid #23715d;outline-offset:2px}ul{padding-inline-start:24px}li{overflow-wrap:anywhere}.highlight{border:2px solid green}</style>
<p id="note"></p><output id="result"></output>
<script>const note=document.querySelector('#note');note.textContent='<strong>Workshop note</strong>';
const result={text:note.textContent,strongCount:note.querySelectorAll('strong').length};
document.querySelector('#result').textContent=JSON.stringify(result);
console.log(JSON.stringify(result));
</script>{"text":"<strong>Workshop note</strong>","strongCount":0}| Inspection | Supplied input or action | Result |
|---|---|---|
| Text | <strong>Workshop note</strong> | Literal tag characters remain |
| Descendant elements | querySelectorAll("strong") | 0 |
Follow the native mechanism
textContent replaces the element’s children with a text node for this nonempty value. It does not run an HTML parser. This mechanism is not a complete sanitization or trust policy; the example uses one harmless supplied string.
Compare the material alternative
innerHTML parses the same fixed string. The tags become an actual strong child, and textContent now contains only its wording.
<style>html{font-size:16px}body{margin:12px;font:1rem/1.5 system-ui,sans-serif;color:#17332d;background:#fff}p{overflow-wrap:anywhere}output{display:block;margin-block:12px;overflow-wrap:anywhere;white-space:pre-wrap}button,input{font:inherit;max-width:100%;box-sizing:border-box}button{margin:4px;padding:8px}label{display:block;margin-block:8px}button:focus-visible,input:focus-visible{outline:3px solid #23715d;outline-offset:2px}ul{padding-inline-start:24px}li{overflow-wrap:anywhere}.highlight{border:2px solid green}</style>
<p id="note"></p><output id="result"></output>
<script>const note=document.querySelector('#note');note.innerHTML='<strong>Workshop note</strong>';
const result={text:note.textContent,strongCount:note.querySelectorAll('strong').length};
document.querySelector('#result').textContent=JSON.stringify(result);
console.log(JSON.stringify(result));
</script>{"text":"Workshop note","strongCount":1}Work the boundary
What happens to an existing strong child when textContent is set to empty text?
Show the worked answer
All children are removed. The resulting text is empty and the child-node count is zero.
<style>html{font-size:16px}body{margin:12px;font:1rem/1.5 system-ui,sans-serif;color:#17332d;background:#fff}p{overflow-wrap:anywhere}output{display:block;margin-block:12px;overflow-wrap:anywhere;white-space:pre-wrap}button,input{font:inherit;max-width:100%;box-sizing:border-box}button{margin:4px;padding:8px}label{display:block;margin-block:8px}button:focus-visible,input:focus-visible{outline:3px solid #23715d;outline-offset:2px}ul{padding-inline-start:24px}li{overflow-wrap:anywhere}.highlight{border:2px solid green}</style>
<p id="note"><strong>Old note</strong></p><output id="result"></output>
<script>const note=document.querySelector('#note');note.textContent='';
const result={text:note.textContent,children:note.childNodes.length};
document.querySelector('#result').textContent=JSON.stringify(result);
console.log(JSON.stringify(result));
</script>{"text":"","children":0}