Slots
A Slot is a high-level interface for developers to define and manage dynamic content insertion within drop-in components.
Context
Section titled âContextâThe context is defined during implementation of a drop-in and can be used to pass data and functions to the slot.
Pre-built Methods
Section titled âPre-built Methodsâ- dictionary: The dictionary of the selected language.
- replaceWith: A function to replace the slotâs content with a new HTML element.
- appendChild: A function to append a new HTML element to the slotâs content.
- prependChild: A function to prepend a new HTML element to the slotâs content.
- appendSibling: A function to append a new HTML element after the slotâs content.
- prependSibling: A function to prepend a new HTML element before the slotâs content.
- getSlotElement: A function to get a slot element.
- onChange: A function to listen to changes in the slotâs context.
Implementing a new slot
Section titled âImplementing a new slotâThe <Slot /> component is used to define a slot in a container. It receives a name and a slot object with the following properties:
The name of the slot in PascalCase. string (required).
slotTag
Section titled âslotTagâThe HTML tag to use for the slotâs wrapper element. This allows you to change the wrapper element from the default div to any valid HTML tag (e.g., âspanâ, âpâ, âaâ, etc.). When using specific tags like âaâ, you can also provide their respective HTML attributes (e.g., âhrefâ, âtargetâ, etc.).
Example:
// Render with a span wrapper<Slot name="MySlot" slotTag="span"> Inline content</Slot>
// Render with an anchor wrapper<Slot name="MySlot" slotTag="a" href="https://example.com" target="_blank"> Link content</Slot>contentTag
Section titled âcontentTagâThe HTML tag to use for wrapping dynamically inserted content within the slot. This is separate from the slotâs wrapper tag and allows you to control how dynamic content is structured. Defaults to âdivâ.
Example:
<Slot name="MySlot" slotTag="article" // The outer wrapper will be an article contentTag="section" // Dynamic content will be wrapped in sections slot={(ctx) => { const elem = document.createElement('div'); elem.innerHTML = 'Dynamic content'; ctx.appendChild(elem); // This will be wrapped in a section tag }}/>slot (required)
Section titled âslot (required)âctx: An object representing the context of the slot, including methods for manipulating the slotâs content.
The slot property, which is implemented as a promise function, provides developers with the flexibility to dynamically generate and manipulate content within slots. However, itâs important to note that this promise is render-blocking, meaning that the component will not render until the promise is resolved.
context
Section titled âcontextâThe context property in the Slot component lets developers pass extra information or functionality to customize how the slot behaves or interacts with the application. This information is accessible within the slotâs rendering logic, allowing for tailored slot behavior based on specific needs or application states.
The render property in the Slot component lets developers define how the content within the slot should be displayed and should be used when developers need fine-grained control over what content appears within the slot. Itâs particularly useful when using custom slot methods (see Privates below) in scenarios where the content to be displayed within the slot is dynamic and may depend on properties passed to another component.
children
Section titled âchildrenâThe children property in the Slot component represents the content that is passed directly within the opening and closing tags of the Slot component. It allows developers to include static content directly within the slot, which will be rendered as part of the slotâs contents. This property is useful for cases where the content within the slot is static or does not need to be dynamically generated by the slot.
// MyContainer.tsx (Drop-in)
import { HTMLAttributes } from 'preact/compat';import { Container, Slot, SlotProps } from '@adobe-commerce/elsie/lib';
export interface MyContainerProps extends HTMLAttributes<HTMLDivElement> { slots?: { MyOpenSlot?: SlotProps<{ // MyOpenSlot Context data: MyContainerData; }>; };}
export const MyContainer: Container<MyContainerProps> = ({ slots, children, ...props}) => { // ...
return ( <div {...props}> <Slot name="MyOpenSlot" slot={slots?.MyOpenSlot} context={{ data }} /> </div> );};Â
// blocks/my-block.js (storefront)
provider.render(MyContainer, { slots: { MyOpenSlot: async (ctx) => { // create a new HTML element const element = document.createElement('div'); // set the innerHTML of the new element to the text from the context's data element.innerHTML = ctx.data.text;
// append the new element to the slot's content ctx.appendChild(element);
// ...or you could also use any of the other slot methods to manipulate the slot's content // ctx.replaceWith(element); // ctx.prependChild(element); // ctx.appendSibling(element); // ctx.prependSibling(element);
// to listen and react to changes in the slot's context (lifecycle) ctx.onChange((next) => { // update the innerHTML of the new element to the new text from the context's data element.innerHTML = ctx.data.text; }); }, },});Privates
Section titled âPrivatesâThe <Slot /> component has a private interface that serves as a mechanism for managing internal
complexity and promoting clean, modular design within the Slot component or related components.
_registerMethod
Section titled â_registerMethodâThe _registerMethod private function is used to register a method in the slotâs context which is particularly helpful in scenarios
where dynamic behavior or interactions need to be incorporated into the Slot component.
Slot Methods also include the ability to modify the slotâs state or content based on external interactions or changes in application state.
_setProps
Section titled â_setPropsâThe _setProps private function within the Slot component is responsible for dynamically updating the properties of the slot.
It allows developers to modify the slotâs state or content based on external interactions or changes in application state,
triggering re-renders of the slot component with updated properties.
_htmlElementToVNode
Section titled â_htmlElementToVNodeâThe _htmlElementToVNode private function in the Slot component converts HTML elements into virtual DOM nodes (VNodes),
enabling their integration into Preact components. This conversion facilitates the dynamic insertion of HTML content
into slots while benefiting from Preactâs virtual DOM reconciliation and rendering.
// MyContainer.tsx (Drop-in)
<Slot name="MyOpenSlot" slot={slots?.MyOpenSlot} context={{ // custom slot method appendButton(callback) { // use _registerMethod to register a method in the slot's context this._registerMethod((...attrs) => { // callback return the values provided by the storefront developer const { text, ...buttonProps } = callback(...attrs);
const button = ( <Button type="button" {...buttonProps}> {text} </Button> );
// use _setProps to update the slot's properties this._setProps((prev: any) => ({ children: [...(prev.children || []), button], })); }); }, }} render={(props) => { // render the slot's content using props mutated by the slot's methods return <Buttons>{props.children}</Buttons>; }}/>Â
// blocks/my-block.js (storefront)
provider.render(MyContainer, { slots: { // Available Slots MyOpenSlot: (ctx) => { ctx.appendButton: (next, state) => { // use state to get the current state of the slot const loading = state.get('loading');
return { text: loading ? 'Loading' : 'Click me!', onClick: async () => { // use state to update the state of the slot state.set('loading', true);
await doSomething().finally(() => { state.set('loading', false); }); }, }; }, }, },});