Create a polyfill to allow to have an "attribute" web component (rather a tag web component)
We are into the age of Web components, but we could at this time only create custom elements, and not custom attributes.
A long time, we used a framework called AngularJs and this framework allowed to create attribute directive
.
With this approach we could introduce the behavior approach such as Wicket where we augment the capability of our component with delegations.
It seems some people such as Rob Eisenberg started some discussion on this topic:
At this time there is no official polyfill, because there is no official proposition yet
On the customElements property, we will find the defineAttribute
method used to declare the name of the custom attribute, and the implementation.
We should extend the CustomAttribute
class which exposes:
- the
connectedCallback
method used when the element where is used the custom attribute is injected into the DOM - the
disconnectedCallback
method used when the element where is used the custom attribute is removed from the DOM - the
attributeChangedCallback
method used when the custom attribute's value has changed - the
element
property which reflects the element where is used the custom attribute
You could see in the demos folder a way to use the polyfill.
Ensure to import the polyfill, through an import:
import '@web-component-attribute-polyfill/browser';
Or from the HTML script
tag:
<script defer="defer" src="./node_modules/@web-component-attribute-polyfill/browser/build/bundle.js">
Then declare your custom attribute:
class BorderStylingAttribute extends globalThis.CustomAttribute {
attributeChangedCallback(name, oldValue, newValue) {
super.attributeChangedCallback(name, oldValue, newValue);
this.applyColor(newValue);
}
connectedCallback() {
super.connectedCallback();
this.element.style.padding = '1rem';
this.element.style.border = '3px solid black';
this.element.style.borderRadius = '1rem';
this.applyColor();
}
applyColor(styling) {
if (styling === 'variant') {
this.element.style.borderColor = 'red';
} else {
this.element.style.borderColor = 'black';
}
}
}
customElements.defineAttribute('border-styling', BorderStylingAttribute);
And at the end, use it on your elements:
<article border-styling="default">Some article tag</article>
<div>
<template shadowrootmode="open">
<article border-styling="default">Some article tag</article>
</template>
</div>
import {
defineAttribute,
enableClosedShadowRoot,
observeAttributes,
CustomAttribute,
} from '@web-component-attribute-polyfill/core';
class BorderStylingAttribute extends CustomAttribute {
attributeChangedCallback(name, oldValue, newValue) {
super.attributeChangedCallback(name, oldValue, newValue);
this.applyColor(newValue);
}
connectedCallback() {
super.connectedCallback();
this.element.style.padding = '1rem';
this.element.style.border = '3px solid black';
this.element.style.borderRadius = '1rem';
this.applyColor();
}
applyColor(styling) {
if (styling === 'variant') {
this.element.style.borderColor = 'red';
} else {
this.element.style.borderColor = 'black';
}
}
}
defineAttribute('border-styling', BorderStylingAttribute);
enableClosedShadowRoot(globalThis); // If we want to be able to look on closed shadow dom
globalThis.addEventListener('DOMContentLoaded', () => {
observeAttributes();
});
And at the end, use it on your elements:
<article border-styling="default">Some article tag</article>
<div>
<template shadowrootmode="open">
<article border-styling="default">Some article tag</article>
</template>
</div>
npm run dev:build
: Build the project over packagesnpm run dev:bump
: Bump the project's version (don't forget to push the commit and the tag)npm run dev:check
: Run tests and styling over packagesnpm run dev:format
: Format files over packagesnpm run dev:format:check
: Check files format over packagesnpm run dev:linting
: Lint files over packagesnpm run dev:publish
: Publish all the packages on npm registrynpm run dev:styling
: Format and lint files over packagesnpm start
: Run the vanilla demonpm run start:ts
: Run the typescript demonpm test
: Run tests over packagesnpm run test:coverage
: Run tests over packages and see coverage reportsnpm run test:integration
: Run integration tests