-
-
Notifications
You must be signed in to change notification settings - Fork 246
Open
Description
Declarative shadow dom is a relatively new feature, but now has cross browser support so it would be good if parse5 could support parsing and serializing declarative shadow roots.
From an API standpoint I think this would look as follows:
- add an option to enable shadowroot parsing/serialization
- note that even in HTML, this is explicitly enabled via using
Document.parseHTMLUnsafe/element.setHTMLUnsafe, existing parsing methods explicitly do not have this behaviour by default
- note that even in HTML, this is explicitly enabled via using
- add a new
shadowRootproperty to element nodes in the default tree adapter - for serialization add an optional list of shadow roots to serialize
For parsing:
- when encountering a
<template shadowrootmode="...">in the parsing stream do not actually append this element to the parent, rather on the tree adapter call some new methodattachDeclarativeShadowRootor similar on the tree adapter - the children of such a template are appended to the resulting shadow root returned from
attachDeclarativeShadowRoot - additional
<template shadowrootmode>` beyond the first should result in these being added as normal children, though it might be worth having an optional hook on the tree adapter to produce warnings (Chrome emits a warning on multiple declarative shadow roots currently for example)
For serializing:
- an additional function
getShadowRootis added, this returns both a shadow root node and flags for the associatedshadowrootdelegatesfocus/shadowrootclonable/shadowrootserializable/shadowrootcustomelementregistryattributes , if and only if the shadow root is serializable then the contents are serialized into a<template>with the appropriate attributes and is added to the element before the rest of the children
As an example:
<!doctype html>
<div>
<template shadowrootmode="open" shadowrootdelegatesfocus="">
<p>Hello world</p>
</template>
</div>const dom = parse5.parse(loadHtml("./example.html"), {
allowDeclarativeShadowRoots: true,
treeAdapter: {
// ...rest of tree adapter
// called when `<template shadowrootmode="open"` is encountered
attachDeclarativeShadowRoot(
element: Element,
// in the example above, this would be { mode: "open", delegatesFocus: true, serializable: false,
{ mode, delegatesFocus, serializable, clonable }: {
mode: "open" | "closed",
delegatesFocus: boolean,
serializable: boolean,
clonable: boolean,
}
) {
element._attachDeclarativeShadowRoot({ mode, delegatesFocus, serializable, clonable });
},
},
});
// ======
const doc2 = new HTMLDocument();
const el = doc2.createElement("div");
const shadowRoot = el.attachShadow({ mode: "closed", clonable: true });
shadowRoot.innerHTML = `<!--contents-->`
doc2.body.append(el);
// same options as https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#gethtmloptions
const html = parse5.serialize(doc2, {
// enable serializing declarative shadow roots
serializableShadowRoots: true,
// force specific shadow roots to be serialized even if not marked
// as serializable
shadowRoots: [shadowRoot],
treeAdapter: {
// returns the associated document fragment that acts as the shadow root
// along with the associated attributes needed for serialization
// this could optionally be a separate type in tree adapter or the current
// DocumentType type could just be re-used
getShadowRoot(element: Element): null | {
shadowRoot: DocumentFragment,
mode: "open" | "closed",
delegatesFocus: boolean,
serializable: boolean,
clonable: boolean,
} {
if (element._shadowRoot === null) return null;
return {
shadowRoot: element._shadowRoot,
mode: element._shadowRoot._mode,
// etc
}
}
},
});
// Effective output: (ignoring whitespace differences)
assertHTMLEqual(html, `
<!doctype html>
<html>
<head></head>
<body>
<div>
<template shadowrootmode="closed" shadowrootclonable="">
<!--contents-->
</template>
</div>
</body>
</html>
`);Metadata
Metadata
Assignees
Labels
No labels