npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

content-change

v1.0.3

Published

Observe and react to changes in distributed nodes in web components, Shadow DOM v0.

Downloads

11

Readme

content-change

Observe and react to changes in distributed nodes in web components, Shadow DOM v0.

It behaves, and is used similarly to Shadow DOM v1's "slotchange" event.

Just 2.1k gzipped

Why

Shadow DOM v0, unlike Shadow DOM v1, has no specification for watching changes to distributed nodes. Because the support for v1 is not as high as v0 at this point, this library exists to provide the ability to watch distribution changes to content elements in v0, while still working with the webcomponents.js polyfill library.

A simple example:

const contentElement = shadow.getElementById('#content');
contentElement.addEventListener('contentchange', event => {
	// React to distributed node changes! Keep reading for details on the event data
});

Install

You can install it from npm

npm install --save content-change

If you're not using package management, you can download a ZIP file and use lib/content-change.min.js.

Setup

The script must be located before web components are imported. If you are using the webcomponents.js polyfill, it doesn't matter if is located before or after the inclusion of webcomponent.js.

<script src="yourpath/content-change.min.js"></script>
<!-- now import your web components -->

This library is UMD wrapped and if you are using a module bundler, you have a couple of different options. You can just import the package to the appropriate location, or you can import the only functions available, watch, and unwatch.

import ContentChange from 'content-change';

// or just import the watch function
import {watch} from 'content-change';

If the library is directly sourced to the window, it operates on the ContentChange global namespace (window.ContentChange).

#Usage Only 1 mutation observer is created per host. No additional MutationObservers are spawned on distributed nodes. Because this library provides functionality that is non-spec, it does not modify the api's and objects of any Shadow DOM behavior.

Specifying which components to watch

A simple call inside of either the createdCallback, or the attachedCallback is made:

ContentChange.watch(hostElement);

watch accepts the host element as an argument.

There is a benefit to this approach as you can specify which components are watched, rather than this library attempting to watch all created components.

Reacting to changes in distributed nodes

The final piece is to specify which content elements should have an event handler. The event is called contentchange and is triggered on content elements. This is done exactly like the slotchange event on the slot elements in Shadow DOM v1.

// get the content element you want to watch for distributed changes in from the shadow dom
const content = shadow.querySelector('selectorForYourContentElement');

content.addEventListener('contentchange', e => {
	console.log(e.detail);
});

Completely stop watching a component

You can stop watching a particular web component completely, but this is different from removing the listeners on the content elements. No longer "watching" the component removes the MutationObserver, giving you back some performance.

ContentChange.unwatch(hostElement);

unwatch accepts the host element as an argument.

Reacting to the different event details

Because the event is created with CustomEvent, the information you will look for in the event will be under the detail key: e.detail. There are three different event type's, you can receive:

  • nodesAdded
  • nodesRemoved
  • mutation

Reacting to newly distributed nodes

The event detail will contain an object that looks like the following:

{
    "type": "nodesAdded",
    "nodesAdded": [Nodes] // An array of added nodes
}

Reacting to nodes that are no longer distributed

The event detail will contain an object that looks like the following:

{
    "type": "nodesRemoved",
    "nodesRemoved": [Nodes] // An array of removed nodes
}

Reacting to mutations in distributed nodes

When a currently distributed node has a mutation occur on it, you will receive the following:

{
    "type": "mutation",
    "mutation": MutationRecord
}

This can be attribute changes, added or removed nodes on the distributed node, characterData changes, etc.

Note: If the mutation causes the node to no longer be distributed, you will receive a nodesRemoved event instead.

Browser support

| Chrome | Firefox | Safari | IE | Edge | Chrome Android | Mobile Safari | |:------:|:-------:|:------:|:--:|:----:|:--------------:|:-------------:| | ✓ | ✓ | 7+ | 11 | ✓ | ✓ | ✓ |

A full example

I will soon make a small github page so that a live example may be viewed. For now, the contents of the files will be placed here:

example-component.html

A simple web component

<template id="example-component">
	<div>I am an example component</div>
	<!-- Distribute paragraphs -->
	<content select="p"></content>
</template>

<script>
	(function () {

		var doc = (document._currentScript || document.currentScript).ownerDocument;
		var objectPrototype = Object.create(HTMLElement.prototype);

		objectPrototype.createdCallback = function () {
			var shadow = this.createShadowRoot();
			var template = doc.querySelector('#example-component');
			shadow.appendChild(template.content.cloneNode(true));

			// Watch this components distributed nodes ("this" is currently the host element)
			window.ContentChange.watch(this);

			var pContent = shadow.querySelector('content[select="p"]');
			pContent.addEventListener('contentchange', function (e) {
				// "this" is the content element
				console.log(this, e.detail);
			});
		};

		document.registerElement('example-component', {
			prototype: objectPrototype
		});

	})();
</script>

index.html

The web page that the web component will be rendered on

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Watch Changes in distributed nodes in Shadow DOM v0</title>

	<script src="https://cdnjs.cloudflare.com/ajax/libs/webcomponentsjs/0.7.23/webcomponents.min.js"></script>
	<script src="lib/content-change.js"></script>
	<link rel="import" href="example-component.html">
</head>
<body>

<example-component>
	<p>This will be a distributed node</p>
</example-component>

<script>
	// Manipulate the example-component so we see changes
	var example = document.querySelector('example-component');
	var p = document.createElement('p');
	p.textContent = 'Dynamically created';

	// Add to the component at some point
	window.setTimeout(function () {
		example.appendChild(p);
	}, 500);

	// Modify a distributed node some point later
	window.setTimeout(function () {
		p.classList.add('foo');
	}, 750);

	// Remove a distributed node
	window.setTimeout(function () {
		example.removeChild(p);
	}, 1000);
</script>

</body>
</html>