Backdraft provides slotting functionality to components using the light DOM.
Why use the light DOM? Until some proposals related to accessibility are implemented as part of the web components spec, there are issues related to accessibility and boundary breaking of the shadow DOM. Given that, if accessibility needs to be supported in an application (which frankly, the answer should be "always"), then slots are not usable at the moment.
Backdraft is based on Daniel Nagy's work on Vampire Slots.
This module is installable through npm.
npm install --save @pynklynn/backdraft
This example demonstrates moving content to a nameless slot.
import { backdraftify } from '@pynklynn/backdraft';
const div = Object.assign(document.createElement('div'), {
innerHTML: backdraftify`
<h4>Example</h4>
<v-slot></v-slot>
`
};
const pTag = document.createElement('p');
pTag.innerHTML = 'This is slotted content';
div.appendChild(pTag);
The above script will produce the following output.
<div>
<bd-root>
<h4>Example</h4>
<bd-slot>
<bd-slot-assigned-content>
<p>This is slotted content</p>
</bd-slot-assigned-content>
</bd-slot>
</bd-root>
</div>
Slots are most useful when combined with custom elements. This is example shows how easy it is to use Vampire with LitElement.
import { backdraftifyLit } from '@pynklynn/backdraft';
import { html, LitElement } from 'lit';
import { customElement } from 'lit/decorators.js'
@customElement('x-example')
@backdraftifyLit
export class ExampleElement extends WithSlots(LitElement) {
render() {
return html`
<h5>Example</h5>
<bd-slot></bd-slot>
`;
}
}
Given the following markup.
<x-example>
<p>This content will be slotted.</p>
<x-example>
The above component will produce the following output when rendered.
<x-example>
<bd-root>
<h5>Example</h5>
<bd-slot>
<bd-slot-assigned-content>
<p>This content will be slotted.</p>
</bd-slot-assigned-content>
</bd-slot>
</bd-root>
<x-example>
https://stackblitz.com/edit/typescript-uykxn4
Backdraft is distributed in ES2022 module format.
A BackdraftRoot
is the root node of a DOM subtree.
A BackdraftSlot
marks the insertion point of foreign content.
BackdraftSlot::name: string = '';
A slot may be given a name so that it can be targeted.
BackdraftSlot::assignedElements(options?: {flatten?: boolean}): Element[];
Returns the elements assigned to this slot. If the flatten
option is set to
true
it will return fallback content if, and only if, there is no assigned
content, otherwise it will still return the assigned content.
BackdraftSlot::assignedNodes(options?: {flatten?: boolean}): Node[];
Returns the nodes assigned to this slot. If the flatten
option is set to
true
it will return fallback content if, and only if, there is no assigned
content, otherwise it will still return the assigned content.
Example
<div>
<bd-root>
<bd-slot></bd-slot>
<bd-slot name="second-slot"></bd-slot>
</bd-root>
<div>This will be moved to the default slot</div>
<div v-slot="second-slot">This will be moved to the second slot.</div>
</div>
interface ISlotChangeEvent extends CustomEvent {
readonly type = 'bd-slot-change';
readonly bubbles = true;
}
The bd-slot-change
event is fired when the slot's assigned content changes.
Example
slot.addEventListener('bd-slot-change', (event: Event) => {
console.log(event.target.assignedNodes());
});
Allows fallback content to be assigned to a slot.
Example
<bd-slot>
<bd-slot-fallback-content>
This will be rendered if no content is assigned to this slot.
</bd-slot-fallback-content>
</bd-slot>
Evergreen browsers are supported.
- Empty
Text
nodes will be assign to a slot and will prevent fallback content from being rendered. - Fallback content cannot contain more slots.