Documentation
Feedback
Guides
Storefront Development

Storefront Development
Store Framework
Concepts
Slots

Slots provide an alternative way for defining component structures within Store Framework themes.

Slots composition is an alternative paradigm for defining component structures within the Store Framework themes. Unlike the conventional block composition method, slots enable developers to pass React props directly to components, providing enhanced flexibility in storefront design.

When using slots, consider the following:

  • The requirement for the blocks attribute is eliminated when implementing components that utilize slots in the Store Theme. Instead, developers can pass the desired blocks as regular props.
  • Slots grant the ability to include any block from any app as a regular prop. Hence, unlike the blocks composition method, declaring the allowed interface attribute is not necessary.

Blocks vs. Slots

To better understand the distinctions between blocks and slots, let's delve into the specifics of each method using a hypothetical hello-world component.

Blocks

When using the blocks composition, the focus revolves around defining allowed blocks and structuring their arrangement. In this approach, the blocks attribute specifies which blocks can be used within the hello-world component. Consider the following example:

HelloWorld.tsxinterfaces.jsonblocks.json

_12
// HelloWorld.tsx
_12
import React from 'react'
_12
import { ExtensionPoint } from 'vtex.render-runtime'
_12
_12
const HelloWorld = () => (
_12
<div className="tc pv5">
_12
<ExtensionPoint id="icon-caret" size={32} />
_12
<h1 className="t-heading-1 c-on-base">Hello, world!<h1>
_12
</div>
_12
)
_12
_12
export default HelloWorld


_10
// interfaces.json
_10
{
_10
"hello-world": {
_10
"component": "HelloWorld",
_10
"allowed": ["icon-caret"]
_10
}
_10
}


_11
// blocks.json
_11
{
_11
"hello-world": {
_11
"blocks": ["icon-caret#point-up"]
_11
},
_11
"icon-caret#point-up": {
_11
"props": {
_11
"orientation": "up"
_11
}
_11
}
_11
}

Note that, in this example, the icon-caret block is the only child block allowed for hello-world. Other limitations of this method include:

  • The hello-world block only accepts the icon-caret block as a child. Any other icon-* block or any block beyond that scope is incompatible, necessitating the explicit allowance of each distinct block in the interfaces.json file.
  • Implementing the block-based approach within HelloWorld.tsx involves conditional logic to identify the block passed by the developer and subsequently convey its ID to the ExtensionPoint component.
  • Passing multiple instances of the same block within the HelloWorld component may lead to rendering problems. For example, passing and rendering both icon-caret#point-up and icon-caret#point-down in the blocks.json file would lead to an ambiguous scenario.

Slots

Now, let's reimagine the same scenario using slots composition:

HelloWorld.tsxinterfaces.jsonblocks.json

_10
import React, { ReactElement } from 'react';
_10
const HelloWorld = ({ Icon }) => (
_10
<div className="tc pv5">
_10
<Icon size={32} />
_10
<h1 className="t-heading-1 c-on-base">Hello, world!</h1>
_10
</div>
_10
);
_10
_10
export default HelloWorld;


_10
// interfaces.json
_10
{
_10
"hello-world": {
_10
"component": "HelloWorld"
_10
}
_10
}


_13
//blocks.json
_13
{
_13
"hello-world": {
_13
"props": {
_13
"Icon": "icon-caret#point-up"
_13
}
_13
},
_13
"icon-caret#point-up": {
_13
"props": {
_13
"orientation": "up"
_13
}
_13
}
_13
}

Note that, by directly passing required components as props, the slots approach eliminates the need for the allowed attribute. This method introduces flexibility into the component integration process, allowing any component to be included as a prop without prior restrictions.

This example demonstrates how slots composition simplifies the component declaration process and enhances flexibility. You can adjust the composition by passing different components as props, making the structure more adaptable to your needs.

To ensure consistent and effective usage of slots, it is important to adhere to the following guidelines:

  • Slots are always exposed via PascalCased props.
✅ Do❌ Don't

_10
{
_10
"props": {
_10
// Works!
_10
"Icon": "icon-caret"
_10
}
_10
}


_10
{
_10
"props": {
_10
// Does NOT work. This will be interpreted as a string by store builder
_10
"icon": "icon-caret"
_10
}
_10
}

  • Nested slots are not supported. This means that you can't have a slot prop inside of an object, such as shown below:

_12
{
_12
"props": {
_12
"somePropThatsAnObject": {
_12
"p1": "this",
_12
"p2": "will",
_12
"p3": "not",
_12
"p4": "work",
_12
// This will NOT be picked up by the store builder
_12
"Slot": "some-block"
_12
}
_12
}
_12
}

Contributors
2
Photo of the contributor
Photo of the contributor
+ 2 contributors
Was this helpful?
Yes
No
Suggest edits (Github)
Contributors
2
Photo of the contributor
Photo of the contributor
+ 2 contributors
On this page