cf.completefrontendCode editorOpen lab
THE JAVASCRIPT FIELD GUIDE

Node properties & contents

Read DOM node types, names, text, HTML, and visibility safely with nodeType, tagName, innerHTML, outerHTML, textContent, innerText, and hidden.

By the end, you can
  • 01
    Identify node kindsRead nodeType, nodeName, tagName, localName, and text-node data without guessing.
  • 02
    Choose a content propertyDecide when to use textContent, innerText, innerHTML, or outerHTML.
  • 03
    Avoid dangerous renderingShow untrusted text safely and understand why HTML strings can become XSS.

The properties dashboard

The DOM tree gives JavaScript objects for everything the browser built: the document, elements, words, comments, and fragments. This lesson is about the small dashboard of properties you read most often once you have a node in your hand.

Some properties identify what kind of node you found: nodeType, nodeName, tagName, and localName. Other properties read or replace the contents: textContent, innerText, innerHTML, and outerHTML. Finally, hidden is a convenient property for toggling the matching HTML attribute.

The one-sentence definition

Node properties let you ask, “what is this node?”, “what text or HTML is inside it?”, and “should this element be hidden?”

Real-life analogyContent properties are labels on a display box

Imagine a display box in a museum. You can ask for the label on the box, the words written inside it, or you can replace its contents entirely. DOM content properties feel similar, but the details matter because the browser is not just storing words; it can parse those words as markup.

In real life: Describing new contents of a box in HTML words
In JavaScript: innerHTML = "<b>bold</b>": the browser throws away old children and rebuilds from the description
In real life: Replacing the box itself
In JavaScript: outerHTML = "<section>...": the old variable still points at the old detached box
In real life: Reading every note inside the box
In JavaScript: textContent: all text node data, including hidden notes
In real life: Reading what a visitor sees
In JavaScript: innerText: rendered text, affected by layout and CSS

Where the analogy stops: A real box does not parse instructions. A browser does: HTML strings become nodes, and that power is exactly why untrusted strings are dangerous.

Start with this tiny replay. It is not a browser debugger; it is a safe model that isolates one question: which string comes back when you read a content property?

Step through one property read
Step 0 of 3Ready
Your turn: follow the blue line

Pick one property, then step through the read. The real browser experiments below use actual DOM nodes; this replay isolates the string each property would expose.

Running in
  1. script
Next: line 1
Click the blue line to take the next stepPop out in the code editor (opens in a new tab)JavaScript
  textContent: "Hello hidden note",  innerHTML: "Hello <span hidden>hidden note</span>",  outerHTML: "<p>Hello <span hidden>hidden note</span></p>",};const picked = card.textContent;console.log(picked);
CallStoreChangeResultRun = next line. Ran = already executed.
Recent returnsNothing yet. Start with the blue line.
Which property should line 6 read?

Change the property, then replay from the top. The browser experiments below use real DOM nodes.

A guided replay recorded from real JavaScript calls, not an engine debugger. Step follows executed statements; Back reviews a snapshot. Reset starts a fresh run.

nodeType, nodeName, tagName, and localName

INTERACTIVE

The broadest test is node.nodeType. It is a number because it comes from older DOM APIs, but the constants are still useful:

Common DOM node identity properties
Node kindnodeTypenodeNametagNamelocalNameUseful value property
Element1Uppercase for HTML elements, like DIVSame as nodeName for elementsLowercase HTML name, like divUsually textContent or element-specific properties
Text3#textDoes not existDoes not existnodeValue or data is the text
Comment8#commentDoes not existDoes not existnodeValue or data is the comment
Document9#documentDoes not existDoes not existdocument.textContent is null
Doctype10The doctype name, usually htmlDoes not existDoes not existdoctype fields such as name
Fragment11#document-fragmentDoes not existDoes not existchildren and textContent

For HTML elements in an HTML document, nodeName and tagName are uppercase: a paragraph reports P. localName is usually the lowercase name you typed, such as p. SVG elements are different: in an HTML document an inline SVG circle reports lowercase tagName and localName. Verify it below in your own browser.

Node inspector
Inspector sketchPop out in the code editor (opens in a new tab)JavaScript
const node = event.target;console.log(node.nodeType);console.log(node.nodeName);console.log(node.tagName);console.log(node.localName);console.log(node.nodeValue);
Common nodeType constants

1 element · 3 text · 8 comment · 9 document · 10 doctype · 11 fragment

Real DOM nodesClick a node
nodeType
—
nodeName
—
tagName
—
localName
—
nodeValue / data
—
Try it yourself
Selected: nothing selected yet

Click the heading, paragraph words, bold word, SVG badge, or the card itself. Text and comment nodes are harder to click directly, so this mini page includes them and the explanation shows how their properties differ. In the SVG, tagName is lowercase in an HTML document.

The mini page is built inside an empty ref container, so React does not own the nodes being inspected.

Notice one professional habit: check whether you have an element before using element-only properties. tagName exists on elements; a text node has nodeName #text and stores its words in nodeValue or data instead.

innerHTML and outerHTML replace by parsing strings

INTERACTIVE

innerHTML is a powerful shortcut: it serializes or parses the children inside an element. Assigning to it is not a tiny edit. The browser throws away the old children and builds new ones from the HTML string. That means old listeners, focus, references, and typed input property values are lost.

Real-life analogyinnerHTML is a rebuild order

If you tell a builder “make the room contain this new list of furniture,” they do not carefully preserve the exact old chair. DOM HTML setters work the same way from your code’s point of view.

In real life: Handing a builder a new room description
In JavaScript: box.innerHTML = "<b>bold</b> text"
In real life: The builder removes the old furniture first
In JavaScript: Old child nodes are discarded
In real life: Your note about the old chair still exists
In JavaScript: A variable can still point at an old node
In real life: But the chair is no longer in the room
In JavaScript: oldChild.isConnected becomes false

Where the analogy stops: Browsers can optimize internally, but the observable behavior is a rebuild: old child node identity and event listeners do not survive.

innerHTML / outerHTML playground
Replacement sketchPop out in the code editor (opens in a new tab)JavaScript
const box = document.querySelector("#box");box.innerHTML = "<b>bold</b> text";box.innerHTML += "<em> rebuilt</em>";const old = box.querySelector("b");old.outerHTML = "<strong>new</strong>";console.log(old.isConnected);
Live containerButton clicks: 0
Old node connected after outerHTML?
not replaced yet
Try it yourself

Type in the input, then try innerHTML +=.

Try this order: type into the input, click the listener button, run innerHTML +=, then click the new button. The listener and typed property value are gone because the children were rebuilt.

outerHTML goes one step farther: it replaces the element itself, not only its children. After old.outerHTML = "...", the page contains the replacement, while old still points at the detached original object. In the browser verified for this lesson, setting outerHTML on document.documentElement throws NoModificationAllowedError because its parent is the document. A detached element assignment did not throw in that browser, but it also did not insert anything because there was no parent to replace it in.

Important XSS nuance

Scripts inserted with innerHTML do not run as normal script tags. That does not make innerHTML safe for user input: event-handler attributes such as onerror can still run.

textContent vs innerText

INTERACTIVE

textContent is about node data. It reads the text of all descendant text nodes, including hidden elements and text inside style or script elements. Setting it replaces the children with one text node, so markup-looking characters are shown literally.

innerText is about rendered text. It is CSS-aware: it skips display: none content, applies effects such as text-transform: uppercase, and turns block boundaries or <br> into line breaks. Because it asks layout what a reader sees, it can trigger layout work. If an element is not being rendered, browsers return the same value as textContent.

textContent vs innerText
Read rendered and raw textPop out in the code editor (opens in a new tab)JavaScript
const panel = document.querySelector("#panel");console.log(panel.textContent);console.log(panel.innerText);
Live valuesBrowser result
textContent
""
innerText
""
Try it yourself

textContent reads text nodes exactly enough to include hidden text and the style element. innerText asks what rendered text a reader would see: hidden text disappears, CSS uppercase is applied, and line breaks are normalized by layout.

This comparison is computed in your browser after mount, because innerText depends on rendering.
Choosing between textContent, innerText, innerHTML, and outerHTML
PropertyReadsWritesBest use
textContentAll descendant text node dataText only; replaces children with textFast, safe text updates
innerTextRendered, human-visible textText only, with rendering rulesCopy-like visible text checks
innerHTMLSerialized child markupParsed child markupTrusted templates or demos only
outerHTMLSerialized element plus childrenParsed replacement for the elementRare full-element replacement

One odd but useful edge case: document.textContent is null. The document is the root container, not a normal element with text children to concatenate.

Untrusted text and XSS

SAFE SANDBOX

Cross-site scripting, usually shortened to XSS, happens when a string from outside your code becomes instructions in your page. A comment, profile name, search term, or chat message should be text. If you put it into innerHTML, you let the string become markup.

Real-life analogyLetting a stranger write on your shop display

You can safely write a visitor's name on your shop display. Letting the visitor write on it directly is different: the browser may treat their text as page instructions.

In real life: A visitor gives you their name
In JavaScript: User input as plain text
In real life: You write the name on the display
In JavaScript: textContent = userName
In real life: The visitor writes on the display directly
In JavaScript: innerHTML = userName

Where the analogy stops: A real display board cannot run code. The browser can treat untrusted HTML as active instructions.

XSS sandbox: text or instructions?
Unsafe vs safe renderingPop out in the code editor (opens in a new tab)JavaScript
nameSlot.innerHTML = userName; // unsafe for untrusted textnameSlot.textContent = userName; // safe: shows characters
Predefined user name
<img src="data:," onerror="parent.postMessage('ran', '*')">
Sandboxed iframeinnerHTML
Payload message: not received
Try it yourself

No payload message received. With textContent, markup-looking characters appear as text instead of becoming an image with an event handler.

The iframe is sandboxed with scripts allowed only inside the frame. The parent validates event.source before trusting the message.
Safe with untrusted text?
  • textContent
  • innerText
  • innerHTML
  • outerHTML
  • insertAdjacentHTML
  • createTextNode
Try it yourself
0 of 6 correct

Sort each API by whether it treats a string as plain text or as HTML.

Choose a category for every card. You can change an answer at any time; Reset clears them all.

The hidden property

INTERACTIVE

element.hidden reflects the HTML hidden attribute. Set it to true, and the attribute appears. Set it to false, and the attribute is removed. Browsers usually hide matching elements with a user-agent stylesheet rule like [hidden] { display: none; }.

That last sentence hides a trap: it is CSS, not magic. Author CSS can override the browser’s rule. If your stylesheet says a hidden panel is display: flex, the panel can still be visible unless your app includes a stronger rule such as [hidden] { display: none !important; } or toggles a class whose styles win.

hidden is an attribute, CSS still wins
Visibility sketchPop out in the code editor (opens in a new tab)JavaScript
panel.hidden = !panel.hidden;// If author CSS says display: flex, the element can still be visible.// Fix with: [hidden] { display: none !important; }
Live panelhidden: true
Try it yourself

The element has the hidden attribute, but this demo also gives it author CSS with display: flex, so it remains visible. Add the fix to make hidden win again.

hidden="until-found" is a newer value for find-in-page reveal behavior, but not every browser supports it yet.

You may also see hidden="until-found" in newer material. It is meant for content that is hidden until browser find-in-page or fragment navigation reveals it, but not every browser supports it yet. For ordinary toggles, use the boolean hidden property and test your CSS.

Where you will use this

These properties show up in small everyday tasks. A search result title from your server should go into textContent. A trusted icon template might be cloned or inserted with a safe framework mechanism, not assembled from user input. A disclosure panel can use button.ariaExpanded together with panel.hidden so assistive technology and sighted users agree.

Safe message renderingPop out in the code editor (opens in a new tab)JavaScript
function showMessage(slot, message) {
  slot.textContent = message;
}

function toggleDetails(button, panel) {
  const willOpen = panel.hidden;
  panel.hidden = !willOpen;
  button.setAttribute("aria-expanded", String(willOpen));
}

Use the identity properties for defensive code. If a function may receive a text node, a comment, or an element, check node.nodeType before reaching for tagName.

Common misconceptions

  • “Every node has tagName.” Text, comment, document, doctype, and fragment nodes do not. Use nodeName or check nodeType first.
  • “innerHTML += appends safely.” It is still an assignment to innerHTML, so existing children are rebuilt.
  • “Scripts do not run, so innerHTML is safe.” Event-handler attributes and dangerous URLs can still execute behavior. Avoid parsing untrusted strings.
  • “innerText and textContent are synonyms.” innerText asks layout for visible text; textContent reads text nodes.
  • “hidden always wins.” The default hiding comes from CSS. Stronger author CSS can override it.
  • “After outerHTML, my variable points at the new element.” It still points at the old object; query again to get the replacement.

Practice exercises

5 EXERCISES
Exercise 1 · Warm-upRead a comment node

Predict the three console lines.

Starter codePop out in the code editor (opens in a new tab)JavaScript
const node = { nodeType: 8, nodeName: "#comment", data: "todo" };
console.log(node.nodeType);
console.log(node.nodeName);
console.log(node.data);

Answer, then press Check. Spacing and letter case don’t matter.

    Exercise 2 · PracticeChoose the safe property

    A profile name came from a form. Which property should receive it?

    Starter codePop out in the code editor (opens in a new tab)JavaScript
    const userName = "<img src=x onerror=alert(1)>";
    console.log(userName);

    Answer, then press Check. Spacing and letter case don’t matter.

      Exercise 3 · PracticeBuild a tiny inspector

      Write a helper for the browser console that describes a node without crashing on text nodes.

      Starter codePop out in the code editor (opens in a new tab)JavaScript
      function describe(node) {
        // Return type, name, tag, and text data when relevant.
      }
        Exercise 4 · PracticeFind the detached node

        After an element is replaced with outerHTML, is the original variable still connected to the document?

        Answer, then press Check. Spacing and letter case don’t matter.

          Exercise 5 · ChallengeMake hidden win

          What selector would you add to a stylesheet to force hidden elements to stay hidden?

          Starter codePop out in the code editor (opens in a new tab)JavaScript
          .panel[hidden] {
            display: flex;
          }

          Answer, then press Check. Spacing and letter case don’t matter.

            Check your understanding

            7 QUESTIONS
            Node properties quiz · 7 questionsScore: first tries count
            1. Question 1 of 7Which nodeType number means an element node?

              Choose an answer to see the explanation.

            2. Question 2 of 7What does the name comparison print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              console.log("P");
              console.log("p");

              Choose an answer to see the explanation.

            3. Question 3 of 7Which property includes hidden text and the text inside <style> or <script>?

              Choose an answer to see the explanation.

            4. Question 4 of 7What does the detached-node check print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              const old = { isConnected: false };
              console.log(old.isConnected);

              Choose an answer to see the explanation.

            5. Question 5 of 7Why is element.innerHTML += more risky for existing children?

              Choose an answer to see the explanation.

            6. Question 6 of 7Which is safest for showing a user-typed name?

              Choose an answer to see the explanation.

            7. Question 7 of 7What does the hidden property reflect?

              Choose an answer to see the explanation.

            Key takeaways

            • nodeType tells you the broad kind: element 1, text 3, comment 8, document 9, doctype 10, fragment 11.
            • tagName is element-only; nodeName works on every node and uses names like #text.
            • innerHTML and outerHTML parse strings and rebuild nodes. They are for trusted markup, not user text.
            • textContent reads raw text node data. innerText reads rendered text and can trigger layout.
            • hidden reflects an attribute, but CSS decides whether that attribute actually hides the element.

            Final definition: Node content properties are the DOM’s read/write controls for a node’s identity, text, HTML, and hidden state.

            Up next: Attributes & properties.

            CompleteFrontend Clear concepts. Working examples.