shadow-dom-style-sharing
v2.1.0
Published
polyfill ::part and ::theme
Downloads
2
Readme
what is this
polyfills ::theme
and ::part
to support sharing css styling between custom elements
see https://meowni.ca/posts/part-theme-explainer/
for more information on these selectors
setup
install package
npm i -s shadow-dom-style-sharing
import
using as a node modules
const {process} = require('shadow-dom-style-sharing')
using as a es6 modules
import {process} from 'build-path-to-shared-styling/es6/index.js';
using <es6 with no build tool
<script>window.module = {};</script>
<script src="build-path-to-shared-styling/src/index.js"></script>
usage process(root, changed)
invoke process
each time you'd like to update the styling. this will typically need to be done once the DOM loads:
document.addEventListener('DOMContentLoaded', () => {
process(document);
});
and again when new elements are added to the DOM:
let myElement = document.createElement('my-element');
document.appendChild(myElement);
process(document, myElement);
the first argument to process
should be the root element style rules are relative to. This is typically always the document.
the second argument to process
is optional and scopes the style rules to only be added to that element. This is useful to avoid css rule duplication when invoking process
multiple times; e.g. when dynamically adding elements to the DOM after it has loaded.
limitations
syntax
at the moment, to avoid having to re-parse the css styling, we reuse the browser's parsed document.styleSheets
. Unfortunately, browsers prune invalid css
when generating document.styleSheets
. This means we're unable to use custom pseudo-selectors such as ::theme
and ::part
, and instead use the .theme
and .part
syntax. Furthermore, as class selectors, e.g. .part
, can't have parenthetical parameters, we must use .pend
to indicate the end of .part, otherwise it will be assumed to end at the next .theme
, .part
, or ;
.
example
.theme
<!-- styling -->
<style>
.theme .line-orange {
color: orange;
border: 1px solid orange;
}
</style>
<!-- html -->
<p class="line-orange">inline black</p>
<my-element></my-element>
<template id="my-template">
<p class="line-orange">element orange</p>
<my-element-nested part="nested-element"></my-element-nested>
<div part="nested-div">
<p class="line-orange">nested div orange</p>
</div>
</template>
<template id="my-element-nested">
<p class="line-orange">nested element orange</p>
</template>
<!-- set up custom elements -->
<script>
customElements.define('my-element', class extends HTMLElement {
constructor() {
super();
this.attachShadow({mode: 'open'});
const template = document.getElementById('my-template').content.cloneNode(true);
this.shadowRoot.appendChild(template);
}
});
customElements.define('my-element-nested', class extends HTMLElement {
constructor() {
super();
this.attachShadow({mode: 'open'});
const template = document.getElementById('my-element-nested').content.cloneNode(true);
this.shadowRoot.appendChild(template);
}
});
</script>
<!-- apply shared css styling -->
<script type="module">
import {process} from '../es6/index.js';
document.addEventListener('DOMContentLoaded', () => process(document));
</script>
.part
<!-- styling -->
<style>
my-element .part line-orange,
my-element .part nested-element .partend .part nested-line-orange,
my-element .part nested-div .partend .line-orange {
color: orange;
border: 1px solid orange;
}
</style>
<!-- html -->
<p class="line-orange">inline black</p>
<my-element></my-element>
<template id="my-template">
<p part="line-orange">element black</p>
<my-element-nested part="nested-element"></my-element-nested>
<div part="nested-div">
<p class="line-orange">nested div orange</p>
</div>
</template>
<template id="my-element-nested">
<p part="nested-line-orange">nested element part orange</p>
</template>
<!-- set up custom elements -->
<script>
customElements.define('my-element', class extends HTMLElement {
constructor() {
super();
this.attachShadow({mode: 'open'});
const template = document.getElementById('my-template').content.cloneNode(true);
this.shadowRoot.appendChild(template);
}
});
customElements.define('my-element-nested', class extends HTMLElement {
constructor() {
super();
this.attachShadow({mode: 'open'});
const template = document.getElementById('my-element-nested').content.cloneNode(true);
this.shadowRoot.appendChild(template);
}
});
</script>
<!-- apply shared css styling -->
<script type="module">
import {process} from '../es6/index.js';
document.addEventListener('DOMContentLoaded', () => process(document));
</script>
styling dynamically modified dom
<!-- styling -->
<style>
.theme .line-orange {
color: orange;
border: 1px solid orange;
}
</style>
<!-- html -->
<p class="line-orange">inline black</p>
<my-element></my-element>
<template id="my-template">
<p class="line-orange">element orange</p>
<div id="nested-element-placeholder"></div>
<div part="nested-div">
<p class="line-orange">nested div orange</p>
</div>
</template>
<template id="my-element-nested">
<p class="line-orange">nested element orange</p>
</template>
<!-- set up custom elements -->
<script>
customElements.define('my-element', class extends HTMLElement {
constructor() {
super();
this.attachShadow({mode: 'open'});
const template = document.getElementById('my-template').content.cloneNode(true);
this.shadowRoot.appendChild(template);
}
});
customElements.define('my-element-nested', class extends HTMLElement {
constructor() {
super();
this.attachShadow({mode: 'open'});
const template = document.getElementById('my-element-nested').content.cloneNode(true);
this.shadowRoot.appendChild(template);
}
});
</script>
<!-- apply shared css styling -->
<script type="module">
import {process} from '../es6/index.js';
document.addEventListener('DOMContentLoaded', () => process(document));
setTimeout(() => {
let nestedElement = document.createElement('my-element-nested');
document.querySelector('my-element').shadowRoot.querySelector('#nested-element-placeholder').appendChild(nestedElement);
process(document, nestedElement);
}, 500);
setTimeout(() => {
let nestedElement = document.createElement('my-element-nested');
document.querySelector('my-element').shadowRoot.querySelector('#nested-element-placeholder').appendChild(nestedElement);
process(document, nestedElement);
}, 1000);
</script>
this markdown was generated by de-document-examples