diff --git a/README.md b/README.md
index a960cde..496c70d 100644
--- a/README.md
+++ b/README.md
@@ -14,10 +14,10 @@ const Greeting = ({ name = 'World' }) => (
Hello, {name}!
);
-register(Greeting, 'x-greeting', ['name'], { shadow: true, mode: 'open', adoptedStyleSheets: [] });
-// ^ ^ ^ ^ ^ ^
-// | HTML tag name | use shadow-dom | use adoptedStyleSheets
-// Component definition Observed attributes Encapsulation mode for the shadow DOM tree
+register(Greeting, 'x-greeting', ['name'], { shadow: true, mode: 'open', adoptedStyleSheets: [], serializable: true });
+// ^ ^ ^ ^ ^ ^ ^
+// | HTML tag name | use shadow-dom | use adoptedStyleSheets |
+// Component definition Observed attributes Encapsulation mode for the shadow DOM tree Root is serializable
```
> _**\* Note:** as per the [Custom Elements specification](https://html.spec.whatwg.org/multipage/custom-elements.html#valid-custom-element-name), the tag name must contain a hyphen._
@@ -81,7 +81,7 @@ register(FullName, 'full-name');
### Passing slots as props
-The `register()` function also accepts an optional fourth parameter, an options bag. At present, it allows you to opt-in to using shadow DOM for your custom element by setting the `shadow` property to `true`, and if so, you can also specify the encapsulation mode with `mode`, which can be either `'open'` or `'closed'`.
+The `register()` function also accepts an optional fourth parameter, an options bag. At present, it allows you to opt-in to using shadow DOM for your custom element by setting the `shadow` property to `true`, and if so, you can also specify the encapsulation mode with `mode`, which can be either `'open'` or `'closed'`. Additionally, you may mark the shadow root as being serializable with the boolean `serializable` property.
When using shadow DOM, you can make use of named `` elements in your component to forward the custom element's children into specific places in the shadow tree.
diff --git a/src/index.d.ts b/src/index.d.ts
index 8fc37c3..3703fe9 100644
--- a/src/index.d.ts
+++ b/src/index.d.ts
@@ -8,6 +8,7 @@ type Options =
shadow: true;
mode?: 'open' | 'closed';
adoptedStyleSheets?: CSSStyleSheet[];
+ serializable?: boolean;
};
/**
diff --git a/src/index.js b/src/index.js
index 5148a0d..1ae5828 100644
--- a/src/index.js
+++ b/src/index.js
@@ -15,7 +15,10 @@ export default function register(Component, tagName, propNames, options) {
inst._vdomComponent = Component;
if (options && options.shadow) {
- inst._root = inst.attachShadow({ mode: options.mode || 'open' });
+ inst._root = inst.attachShadow({
+ mode: options.mode || 'open',
+ serializable: options.serializable ?? false,
+ });
if (options.adoptedStyleSheets) {
inst._root.adoptedStyleSheets = options.adoptedStyleSheets;
diff --git a/test/index.test.jsx b/test/index.test.jsx
index 4fce9fe..734ab6c 100644
--- a/test/index.test.jsx
+++ b/test/index.test.jsx
@@ -421,4 +421,47 @@ describe('web components', () => {
'Light DOM Children
'
);
});
+
+ it('supports the `serializable` option', async () => {
+ function SerializableComponent() {
+ return Serializable Shadow DOM
;
+ }
+
+ function NonSerializableComponent() {
+ return Non-serializable Shadow DOM
;
+ }
+
+ registerElement(SerializableComponent, 'x-serializable', [], {
+ shadow: true,
+ serializable: true,
+ });
+
+ registerElement(NonSerializableComponent, 'x-non-serializable', [], {
+ shadow: true,
+ });
+
+ root.innerHTML = `
+
+
+ `;
+
+ const serializableEl = document.querySelector('x-serializable');
+ const nonSerializableEl = document.querySelector('x-non-serializable');
+
+ assert.isTrue(serializableEl.shadowRoot.serializable);
+ assert.isFalse(nonSerializableEl.shadowRoot.serializable);
+
+ const serializableHtml = serializableEl.getHTML({
+ serializableShadowRoots: true,
+ });
+ const nonSerializableHtml = nonSerializableEl.getHTML({
+ serializableShadowRoots: true,
+ });
+
+ assert.equal(
+ serializableHtml,
+ 'Serializable Shadow DOM
'
+ );
+ assert.isEmpty(nonSerializableHtml);
+ });
});