Skip to content
Merged
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ const Greeting = ({ name = 'World' }) => (
<p>Hello, {name}!</p>
);

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._
Expand Down Expand Up @@ -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 `<slot>` elements in your component to forward the custom element's children into specific places in the shadow tree.

Expand Down
1 change: 1 addition & 0 deletions src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ type Options =
shadow: true;
mode?: 'open' | 'closed';
adoptedStyleSheets?: CSSStyleSheet[];
serializable?: boolean;
};

/**
Expand Down
5 changes: 4 additions & 1 deletion src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
43 changes: 43 additions & 0 deletions test/index.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -421,4 +421,47 @@ describe('web components', () => {
'<h1>Light DOM Children</h1><div><slot><p>Child 1</p><p>Child 2</p></slot></div>'
);
});

it('supports the `serializable` option', async () => {
function SerializableComponent() {
return <div>Serializable Shadow DOM</div>;
}

function NonSerializableComponent() {
return <div>Non-serializable Shadow DOM</div>;
}

registerElement(SerializableComponent, 'x-serializable', [], {
shadow: true,
serializable: true,
});

registerElement(NonSerializableComponent, 'x-non-serializable', [], {
shadow: true,
});

root.innerHTML = `
<x-serializable></x-serializable>
<x-non-serializable></x-non-serializable>
`;

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,
'<template shadowrootmode="open" shadowrootserializable=""><div>Serializable Shadow DOM</div></template>'
);
assert.isEmpty(nonSerializableHtml);
});
});