Update: My initial answer is garbage. My problem was that I was trying to get currentScript.ownerDocument from a method inside the class, and not actively running in the script in the current document (for example, in IIFE, where I define the class, and therefore where the script will work next to the template ) The method can be called from another script, "currentScript" at that moment (i.e., Maybe another document in general, especially if you import from another import, like me).
So this is bad:
class Foo extends HTMLElement { constructor() { const template = document.currentScript.ownerDocument.querySelector("template");
and this is better:
(() => { const _template = document.currentScript.ownerDocument.querySelector("template"); class Foo extends HTMLElement { constructor() {
Hope this helps someone who is dumb like me.
Original answer:
I also had problems trying to access templates from an import hierarchy of some depth. The currentScript did not work for me in this case: in Chrome / Chromium, currentScript always referred to the first import, but never with any of the deeper imports (as I mentioned in the comment to @acdcjunior's answer), and in Firefox (via polyfill) currentScript was null .
So I ended up doing something similar to @Caranicas answer. I created a utility function that finds the imported file, calls it outside the class in IIFE, and then makes it a class property, for example:
index.html
var _resolveImport = function(file) { return (function recur(doc) { const imports = doc.querySelectorAll(`link[rel="import"]`); return Array.prototype.reduce.call(imports, function(p, c) { return p || ( ~c.href.indexOf(file) ? c.import : recur(c.import) ); }, null); })(document); }
SIC / app.html:
<link rel="import" href="src/component.html"> <template>...</template> <script> ((global) => { const _import = global._resolveImport("src/app.html"); class App extends HTMLElement { static get import() { return _import; } connectedCallback() { this.render(); this.$component = new global.Component(); } render() { let template = this.constructor.import.querySelector("template"); </script>
SIC / component.html:
<template>...</template> <script> ((global) => { const _import = _resolveImport("src/component.html"); class Component extends HTMLElement { static get import() { return _import; } render() { let template = this.constructor.import.querySelector("template"); </script>
_resolveImport is expensive, so it would be nice to call it more than once for each import, and only for an import that actually needs it.