Skip to main content
Ben Nadel at cf.Objective() 2009 (Minneapolis, MN) with: Jean Ducrot
Ben Nadel at cf.Objective() 2009 (Minneapolis, MN) with: Jean Ducrot

Using Node.contains() To Determine If One DOM Node Is Inside Another

By on

This post is primarily a "Note to Self"; but, the other day, I was reading through the Mozilla Developer Network (MDN) site - as you do - and I noticed that the Node interface in the Document Object Model (DOM) API has a .contains() method. This method checks to see if one node is contained within, or is equal to, another node. In jQuery, I used to use the .contains() method all the time for this type of investigation. However, when it came to the native DOM, I've historically walked up the tree comparing object references. I'm shocked that I didn't know that the native DOM API contained a similar helper. As such, I'm documenting it here in an effort to drive this information into my head.

Run this demo in my JavaScript Demos project on GitHub.

View this code in my JavaScript Demos project on GitHub.

As you can see from earlier posts, like "Tracking Click Events Outside The Current Component In Angular 2 Beta 1", if I wanted to compare the relative relationship of two nodes in the DOM, I would start at one node and continue walking up the parentNode chain until the two references were the same; or, until I ran out of parentNode references to inspect. Such an approach looked something like this:

function isLocalNode( node, target ) {

	do {

		if ( node === target ) {

			return( true );

		}

		target = target.parentNode;

	} while ( target );

	return( false );

}

This worked well. And, it wasn't all that complicated. But, it turns out that I can completely offload this logic to the native Node.contains() method. To see this in action, I've created a simple demo in which you can click anywhere in the page and I'll log to the console whether or not the target node is local to a known container:

<!doctype html>
<html lang="en">
<head>
	<meta charset="utf-8" />
	<title>
		Using Node.contains() To Determine If One DOM Node Is Inside Another
	</title>

	<link rel="stylesheet" type="text/css" href="./demo.css">
</head>
<body>

	<h1>
		Using Node.contains() To Determine If One DOM Node Is Inside Another
	</h1>

	<p>
		This node is <strong>outside</strong> the <em>red node</em>.
	</p>

	<div class="container">
		<p>
			This node is <strong>inside</strong> the <em>red node</em>.
		</p>

		<blockquote>
			<p>
				<em>As is <u>this one</u>!</em>
			</p>
		</blockquote>
	</div>

	<p>
		This node is <strong>outside</strong> the <em>red node</em>.
	</p>

	<script type="text/javascript">

		var container = document.querySelector( "div.container" );

		// For the demo, we're going to use event-delegation on the document in order to
		// allow the user to select any element on the page.
		document.addEventListener( "click", handleClick, false );

		// --------------------------------------------------------------------------- //
		// --------------------------------------------------------------------------- //

		// I handle the event-delegation and check for the relative node relationship.
		function handleClick( event ) {

			console.group( "Checking Containership" );
			console.log( "Container:", container );
			console.log( "Target:", event.target );
			console.log( "Is Local:", isLocalNode( container, event.target ) );
			console.groupEnd();

		}

		// I determine if the given target is equal-to or contained within the given node.
		function isLocalNode( node, target ) {

			// In Internet Explorer (IE), Node.contains() only works on Element nodes,
			// not Text nodes. As such, let's travel up to the nearest Element node.
			// --
			// NOTE: This doesn't necessarily apply to this demo, which only reacts to
			// Element node interactions. However, I'm adding it here as a mental note.
			while ( target && ( target.nodeType !== Node.ELEMENT_NODE ) ) {

				target = target.parentNode;

			}

			return( node.contains( target ) );

		}

	</script>

</body>
</html>

As you can see, I'm using event-delegation to handle the click event. Then, taking the target of the click event, I'm using the Node.contains() method to see if the click target is contained within (or is equal to) the given container.

In this case, I'm ensuring that the target node is an Element node. While this demo only allows for Element node selection, I've added this one additional piece of logic as a mental note for Internet Explorer (IE) 11. I came across the Node.contains() method while playing with the Selection API. And, when selecting text, it's easy to end up with a Text node instead of an Element node. And, in IE, the Node.contains() method only works for Element nodes.

That said, if we run this code in the browser and click outside and then inside the red box, we get the following output:

Using the Node.contians() method to check containership.

As you can see, we were able to use the Node.contains() method to check if the click target Element was contained within (or was equal to) the given container.

Hopefully, after writing this up, it will stick in my head!

Want to use code from this post? Check out the license.

Reader Comments

I believe in love. I believe in compassion. I believe in human rights. I believe that we can afford to give more of these gifts to the world around us because it costs us nothing to be decent and kind and understanding. And, I want you to know that when you land on this site, you are accepted for who you are, no matter how you identify, what truths you live, or whatever kind of goofy shit makes you feel alive! Rock on with your bad self!
Ben Nadel