shadow

command
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 28, 2026 License: BSD-3-Clause Imports: 8 Imported by: 0

Documentation

Overview

Command shadow gives every custom element a declarative shadow root, and gives it exactly once, so the same page can go through twice without gaining two.

$ shadow -t my-card=card.html -t my-badge=badge.html page.html
4 hosts, 1 already had a shadow root, 3 given one
  my-card      2 given
  my-badge     1 given, 1 already had one

A declarative shadow root is a <template shadowrootmode="open"> child of its host, and the parser attaches it when the template's end tag arrives. So inserting one is an insertion into the host - and the question is where in the host, which turns out to matter more than it looks.

Why the end tag and not the start tag

Two reasons, and both are measurements rather than preferences.

The first is that a rewrite that inserts at the start tag cannot know whether it is needed. A host that already has a shadow root must be left alone, and whether it has one is only known once its children have gone past - by which time the start tag is behind the rewriter and nothing can be inserted there. Inserting at the end tag puts the decision after the evidence: the detecting handler for `my-card > template[shadowrootmode]` has already run or it has not.

The direct-child part of that selector is load-bearing. A declarative shadow root is a child of its host, and a template deeper inside is an ordinary template:

<my-card><div><template shadowrootmode="open">…</template></div></my-card>

my-card > template[shadowrootmode]     matches 0
template[shadowrootmode]               matches 1

The second reason is that the two ways of inserting at the end of an element are not the same when the source omits the end tag. On `<ul><li>a<li>b<li>c</ul>`, where the rewriter has each item still open inside the last:

source                      <ul><li>a<li>b<li>c</ul>
Append per item             <ul><li>a<li>b<li>c[A1]</ul>
EndTag.Before per item      <ul><li>a<li>b<li>c[B3][B2][B1]</ul>
After per item              <ul><li>a<li>b<li>c</ul>[C1]

Append keeps the outermost item's insertion and silently discards the other two. So does After, outside the list. EndTag.Before keeps all three, innermost first, because all three handlers run at the one `</ul>`. Neither position is right - the content belongs at each item's own end, and there is no such position in the source - but one of them loses content and the other does not, and a rewrite whose whole job is to add something should be the kind that does not lose it. Every one of these is silent: no error either way.

What it cannot do

A host whose end tag never arrives gets nothing, because an end-tag handler for an element nothing closes never runs. `<my-card/>` is the case that costs someone an afternoon: HTML ignores the slash on an element that is neither void nor foreign, so the host opens and runs to the end of the document. lolhtml.Element.IsSelfClosing reports true and lolhtml.Element.CanHaveContent also reports true, so neither is a test for it. The report counts those hosts rather than pretending they were done.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL