How to show HTML comments with JavaScript
Tags: html, javascript
Published: 2020-02-05 13:17:07

---
title: How to show HTML comments with JavaScript
published: true
description: A guide on how to display HTML comments with JavaScript
tags: html, javascript
---

Comments are __recommended practice__ in programming and software development in general, they can state a reason why a coding decision was taken or explain what needs to be done to improve the code you are working on.

HTML might not be considered as a programming language but it sure has _comments_. In HTML comments are mostly used to indicate segments of code like the _header_, _sidebar_ or _custom components_.

Comments don't show up in your HTML (as in any language that has comments) but, you can display them on the page for __debugging__ purposes.

Let's find out how we can actually pull this off.

<hr>

HTML tags (including HTML comments) are represented as _nodes_ in the [DOM](https://dev.to/ziizium/the-document-object-model-3n8o) tree and each _node_ has `nodeType` property which is a _numerical value_ that identifies the type of node.

In order to get the numerical value, the format is `node.nodeType`  where _node_ is an HTML element. The numerical value is a value greater than `1`.

The table below lists the possible return values.

| Value        | Meaning       |
| ------------- |:-------------:|
| 1      | ELEMENT_NODE |
| 2      | ATTRIBUTE_NODE     |
| 3 | TEXT_NODE|
| 4 | CDATA_SECTION_NODE|
| 5 | ENTITY_REFERENCE_NODE|
| 6 | ENTITY_NODE|
| 7 | PROCESSING_INSTRUCTION_NODE|
| 8 | COMMENT_NODE|
| 9 | DOCUMENT_NODE|
| 10 | DOCUMENT_TYPE_NODE|
| 11 | DOCUMENT_FRAGMENT_NODE|
| 12 | NOTATION_NODE|

From the table above its evident that HTML comments have a numerical value of `8`, this is the __crucial requirement__ to actually get the comment and then show it on any part of the page.

The other requirement is the `data` value. The `data` as the name implies is the __content of the node__.

![node data in JavaScript](https://dev-to-uploads.s3.amazonaws.com/i/9srd7zm56suykm6d1s4k.PNG)<figcaption>A sample node data</figcaption>

Here is the HTML code:

```html
<noscript style="color: red; text-align: center; text-decoration: underline;">
		<p>The core functionality of this app requires
JavaScript to work. Please enable JavaScript</p>
	</noscript>

	<div class="container">

		<!-- Information -->
		<div class="show" id="comments_section">

			<button class="btn remove-paragraph" id="remove-paragraph" title="Close"></button>

			<p id="number_of_comments"></p>

			<button id ="view_comments" class="btn success">Yes</button>
			<button id ="dont_view_comments" class="btn">No</button>

			<button class="btn success" id="show_comments">Show Comments</button>
			<button class="btn" id="hide_comments">Hide Comments</button>

			<div id="commentsInCode">
				<h2 style="display: none;" id="comment_subheading">Comments in your code</h2>
			</div>
		</div>

		<!-- A dummy text -->
		<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
		tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
		quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
		consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
		cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
		proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
	
	</div>
    
    <script>
        // JS code here
    </script>
```

And the CSS:

```css
p {
    font-weight: bold;
    line-height: 1.618;
    font: 18px Georgia;
}

pre {
    font-weight: bold;
    text-decoration: underline;
    font-family: Georgia;
}

.container {
    width: 70%;
    margin: 0 auto;
}

.form__label {
    display: block;
    margin-bottom: 0.6em;
}

.btn {
    border: none;
    padding: 1.2em;
    background-color: #cd5b45;
    color: #ffffff;
}

.btn.success {
    background-color: green;
}

.btn:hover {
    cursor: pointer;
}

.hidden {
    display: none;
}

.show {
   display: block;
}

#comments_section {
    border: 2px solid #1560bd;
    box-shadow: -3px 3px #1560bd;
    padding: 1.2em;
    position: relative;
}

.remove-paragraph {
    padding: 0.8em;
    position: absolute;
    top: 0em;
    right: 0em;
    border: 50%;
}

.remove-paragraph:hover {
    cursor: pointer;
    font-weight: bold;
}

.remove-paragraph::before {
    content: 'x';
}

#commentsInCode {
    background-color: #cccccc;
}

#commentsInCode pre {
    padding: 1em;
}

#commentsInCode h2 {
    text-align: center;
}

.hidden {
    display: none;
}

.show {
   display: block;
}
```
Taking a look at the HTML, you'll notice we use `id's`. The first thing we'll do in our script is to create variables. Among the variables is an _accumulator_ that'll keep track of the comments found in the code segment.

```javascript
/**
  * querySelector. jQuery style
  * Inspiration from Todd Motto
  * https://ultimatecourses.com/blog/attaching-event-handlers-to-dynamically-created-javascript-elements
  */

let $ = function (selector) {
    return document.querySelector(selector);
};

// variables
let container = $('.container');
let comments_section = $('#comments_section');
let dont_view_comments = $('#dont_view_comments');
let view_comments = $('#view_comments');
let number_of_comments = $('#number_of_comments');
let hide_comments = $('#hide_comments');
let show_comments = $('#show_comments');
let remove_paragraph = $('#remove-paragraph');
let commentsInCode = $('#commentsInCode');
let comment_subheading = $('#comment_subheading');
let accumulator = 0;
```

We need to know the number of comments, therefore, we loop through the `childNodes` and when we encounter a `nodeType` with a value of `8` we increment the accumulator.

```javascript
for (let i = 0; i < container.childNodes.length; i++) {

	// save the childnode in a variable for
	// easy referencing
	let e = container.childNodes[i];

	if (e.nodeType === 8) { // we found a comment!

		// increment the accumulator
		accumulator += 1;

		// show the comments section
		comments_section.style.display = "block";

	}

}
```

We gladly tell the user the number of comments.

```javascript
// Tell the user the number of comments found
number_of_comments.innerHTML =
"<p>We found " + accumulator + " comment(s) in the selected
section of code, will you like to see them?";
```

On initial page load we hide three HTML buttons:

* `show_comments`
* `hide_comments`
* `remove_paragraph` 

```javascript
/**
  * On initial page load, hide the "show",
  * hide" remove paragraph buttons
  */
show_comments.classList.toggle('hidden');
hide_comments.classList.toggle('hidden')
remove_paragraph.classList.toggle('hidden');
```

We attach an _event listener_ to the  _view comments_ button. Inside the _event listener_ we loop through the `childNodes` to find the comments then we create `div` and `pre` tag that will contain the `data`. The `pre` tag is then attached to the `div` tag which in turn is attached to the page via the `appendChild()`  method and the _comment subheading_ is shown.

The `view_comments` and `dont_view_comments` are hidden then we show the `hide_comments` and `remove_paragraph` buttons.

```javascript
view_comments.addEventListener('click', function() {

	// loop through the childnodes
	for (let i = 0; i < container.childNodes.length; i++) {

		// save the childNodes in a variable
		// for easy referencing 
		let e = container.childNodes[i];

		if (e.nodeType === 8) { // we found a comment

			/**
			  * create a text node with the "data", 
			  * after which we create a div and pre
			  * elements.
			  *
			  * The data is attached to the pre tag
			  * and the pre tag to the created div
			  * which in turn is attached to a section
			  * on the page
			  */
			let text = document.createTextNode(e.data);
			let div = document.createElement('div');
			let pre = document.createElement('pre');
		    pre.appendChild(text);
		    div.appendChild(pre);
    		commentsInCode.appendChild(div);
    		comment_subheading.style.display = "block";
		}
	}

	/**
	  * We are using four buttons to make things simple
	  * after the user click yes to view the comments
	  * we hide the "yes" and "no"buttons. Afterward,
	  * we show the "hide" and "remove" paragraph
	  * buttons
	  */
	view_comments.classList.toggle("hidden");
	dont_view_comments.classList.toggle("hidden");
	hide_comments.classList.toggle("show");
	remove_paragraph.classList.toggle("show");
});
```

If the user prefers not to view the comments we close the _comments section_ entirely:

```javascript
// a button to close the comments section on initial
// page load
dont_view_comments.addEventListener('click', function() {
    comments_section.style.display = 'none'; 
});
```

Once the user decides to see the comments, we toggle two buttons _on_ and _off_ when clicked by the user &mdash; the _hide comments_ and _show comments_.

```javascript
/**
  * Add an event listener to the hide, show,
  * dont view comments and view comments buttons
  */ 
hide_comments.addEventListener("click", function() {
    commentsInCode.style.display = "none";
    hide_comments.style.display = "none";
    show_comments.style.display = "block";
});

show_comments.addEventListener("click", function() {
    hide_comments.style.display = "block";
    commentsInCode.style.display = "block";
    show_comments.style.display = "none";
});
```

Finally, we provide an alternative for the user to close the entire _comments section_.

```javascript
// a button to close the entire comments section
remove_paragraph.addEventListener("click", function()  {
    comments_section.style.display = "none";
});
```

The image below is an example of this code in action:

![An image with text](https://dev-to-uploads.s3.amazonaws.com/i/43ebn5fxuglq8gfxzusz.png)<figcaption>An example showing two comments was found by the script</figcaption>

###__Limitations__

This approach does not take comments in a child element into consideration. For example:

```html
<div>
  <!-- comment -->
   <div class="child element">
      <!-- This approach won't see this comment -->
   </div>
</div>
```

###__Conclusion__

This is useful for debugging purposes. The code is _hacky_ but it works. It's up to you to improve the code or better still, turn it into a _function_ that accepts a _selector_ as an argument.

###__Reference__ 

* [The Document Object Model :: Eloquent JavaScript](https://eloquentjavascript.net/14_dom.html)
* [DOM: Node Type, Node Name, Node Value](http://xahlee.info/js/js_get_node_info.html)

_Have fun!_