I do not use any frameworks and try to create an HTML content template with <template
and slot
s for using it in slightly modified ways in my main document. I could use JavaScript string templates and add it to the document
but would prefer to have the HTML not pollute my script file.
The setup is like this:
Definition:
template.html
<template id="my-template">
<style>
/*** static style attributes ***/
.myTemplate {
position: relative;
--radius: 30px; /* I gladly take <slot> here if possible */
}
.myTemplate > .drawing {
height: 100%;
}
.myTemplate > .text {
font-size: 1em;
position: absolute;
top: 50%; left: 50%;
transform: translate(-50%, -50%);
}
.myTemplate circle {
/* e.g. stroke width should be related to the radius, ignore setting the radius */
stroke-width: calc(.5 * var(--radius));
/* imagine several more depending attributes */
}
</style>
<div class="myTemplate">
<div class="drawing">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
<circle cx="50%" cy="50%" r="30"
/>
</svg>
</div>
<div class="text"><slot name="text">foo</slot></div><!-- this slot wobks as expected -->
</div>
</template>
and
style.css
/* free to modify style attributes */
.myTemplate {
height: 300px;
width: 300px;
font-size: 100px;
background: yellow;
}
.myTemplate circle {
fill: #fff0;
stroke: #e28;
}
Expected usage:
script.js
const templateContent = document.getElementById('my-template').content;
let clone1 = templateContent.cloneNode(true);
clone1.querySelector('slot[name=text]').textContent = 'bar';
document.body.appendChild(clone1);
let clone2 = templateContent.cloneNode(true);
clone2.querySelector('slot[name=text]').textContent = 'baz';
// clone2.querySelector('slot[name=radius]').textContent = 22; /* no luck here */
// clone2.style.setProperty('--radius', '22'); /* does not work as well*/
document.body.appendChild(clone2);
So, there are several attributes which base on the same value (here: --radius
) and of course I would like to just set this one value instead of half a dozen others.
I neither could make this work using slot
s nor accessing style.
methods of the template’s instance. One crucial aspect is that individual clones must be parametrized differently.
What am I doing wrong? What would be a better approach?
2
Answers
This can be done by modifying the
textContent
property of the style tag. For example if yourtemplate
had the following slug:Then you can do the following JavaScript:
This purely a string replace so you would have to be creative with your names to avoid collisions. I would prefix all of the slots, and you need to accept that your templates contain malformed HTML to begin with, but it will work.
The problem you are having is that you are forgetting that
.content
on atemplate
is returning aDocumentFragment
and not a proper HTML element.So the following won’t work since a
DocumentFragment
doesn’t have a style attribute:But this will work:
P.S.
If you just did something like
.firstElementChild
, you would find the style tag inside the template, rather than the div you want.