I have tried registering custom elements through native javascript and polymer from within a chrome extension with no luck. The issue is documented here.
Uncaught NotSupportedError: Failed to execute 'registerElement' on 'Document': Registration failed for type 'polymer-element'. Elements cannot be registered from extensions.
I am looking for suggestions for using web components in an extension - has anyone done so? My instinct is to register these elements using standard html tags (div, etc...) on the shadow DOM for the time being until it is supported. Any suggestions?
Custom elements and attributes are valid in HTML, provided that: Element names are lowercase and begin with x- Attribute names are lowercase and begin with data-
A custom element extends HTML by allowing you to define a tag whose content is created and controlled by JavaScript code. The browser maintains a CustomElementRegistry of defined custom elements, which maps an instantiable JavaScript class to an HTML tag.
Custom Elements are a feature of modern browsers which allow you to modularise and install your JavaScript components into the browser itself in order to extend it in new and powerful ways. Custom Elements are HTML components which have their own self-contained markup, styling and behaviour.
For me it was sufficient to use @webcomponents/custom-elements
package in my content.js
.
Also webcomponents-sd-ce.js
weights about 80kb and custom-elements.min.js
only 16kb.
Just install it as a dependancy and import it in the content.js
and let your package manager do the rest.
npm i @webcomponents/custom-elements
import '@webcomponents/custom-elements'
This is how I use it in my project popup-tab-switcher.
I believe that all these workarounds are not necessary and custom elements must work for extensions without polyfills. Please vote for the issue in Chrome bugs to draw attention to this flaw.
It is indeed possible. But, a little hacky.
Original Answer
Here are the steps:
registerElement
from being executed within a chrome extension. To overcome it you need to prevent the usage of the native registerElement
in favor of a simulated one (the polyfill). In webcomponents-lite.js
Comment out the following code (and make this more elegant if you'd like:
scope.hasNative = false; //Boolean(document.registerElement);
And voila! the nativeregisterElement
has now been replaced by the polyfill - which chrome does not prevent from using within an extension.
Polymer Web components
You will need to perform the code listed in the step above and in addition, you will need to load polymer via the following code
var link = document.createElement('link');
link.setAttribute('rel', 'import');
link.setAttribute('href', "link_to_your_polymer.html");
link.onload = function() {
// Execute polymer dependent code here
}
UPDATE #1 - Improved solution
After further investigation, I've learned that Polymer would not work in an extension when loaded dynamically. As a result, the above modifications are necessary. A simpler alternative to this is to load polymer into the head in your content script like this:
function loadRes(res) {
return new Promise(
function(resolve, reject) {
var link = document.createElement('link');
link.setAttribute('rel', 'import');
link.setAttribute('href', res);
link.onload = function() {
resolve(res);
};
document.head.appendChild(link);
});
}
loadRes( chrome.extension.getURL("path_to_your_webcomponents-lite.js") ) // You may/may not need webcomponents.js here
.then( loadRes( chrome.extension.getURL("path_to_your_polymer.html") ) )
.then( loadRes( chrome.extension.getURL("path_to_your_custome_component") ) )
.then(function(){
// code that depends on web components
});
YOU MUST add the urls loaded by chrome.extension.getURL
to the web_accessible_resources
portion of your manifest.
The above is necessary since polymer.html must be loaded through an html resource. Read Eric Bidelman's reply here
Please note that you may not need the webcomponents polyfill loaded here if your component already loads them.
Arrived at this problem in July 2017. The straightforward solution I found is to load the latest webcomponents polyfill for custom elements as an extra content script. No code changes necessary in the polyfill file (perhaps feature detection has been improved).
Extract from the manifest:
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["webcomponents-sd-ce.js", "contentscript.js"]
}
]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With