Components

Register component in Shopstory config

Let's imagine the simplest possible component:

import React from "react";

export type CustomComponentProps = {
  color: "white" | "purple" | "green",
  noBorder: boolean
}

export const CustomComponent : React.FC<CustomComponentProps> = (props) => {
  return <div style={{
    border: props.noBorder ? "none" : "2px solid black",
    background: props.color === "white" ? "white" : props.color === "green" ? "#83d1c4" : "#78517c",
    padding: 24,
    display: "flex",
    justifyContent: "center",
    alignItems: "center",
    textAlign: "center"
  }}>
    My custom component
  </div>
}

It displays a box with a border (that can be disabled with noBorder prop) and with background (controlled by a background prop).

To make it available in Shopstory the first thing we must do is to register it in the components array of Shopstory configuration file:

export const shopstoryConfig: Config = {
    // ...
    components: [
      {
        id: "CustomComponent",
        label: "Custom component",
        schema: [
          {
            prop: "color",
            label: "Color",
            type: "select",
            options: [
              "white", "purple", "green"
            ]
          },
          {
            prop: "noBorder",
            label: "Disable border",
            type: "boolean"
          },
        ]
      }
    ]
}

Each component must have a unique id. schema determines the properties that user can change in the Shopstory sidebar panel. Full reference of available field types available here.

Our component is already available in Shopstory but when you try to add it you will see a "Missing" error:

It's because Shopstory can't find the component instance.

Add component instance to ShopstoryProvider

The remaining step is to allow Shopstory find CustomComponent instance. This task is handled by ShopstoryProvider. Let's open src/shopstory/provider.tsx file and add the component instance:

import { ShopstoryProvider } from "@shopstory/core/react";
import { CustomComponent } from "../components/CustomComponent/CustomComponent";

export const DemoShopstoryProvider : React.FC = ({ children }) => {
  return <ShopstoryProvider
    components={{
      CustomComponent
    }}
  >
    { children }
  </ShopstoryProvider>
}

DemoShopstoryProvider must be added as a wrapper to all <ShopstoryCanvas /> and <Shopstory /> component calls. By doing that Shopstory will be able to access all custom component references and render them properly.

pages/shopstory-canvas.tsx:

const ShopstoryCanvasPage: NextPage = () => {
  return <DemoShopstoryProvider>
    <Canvas config={shopstoryConfig} />
  </DemoShopstoryProvider>
}

/pages/shopstory-block/[entryId].tsx:

const ShopstoryBlockPage: NextPage<ShopstoryBlockPageProps> = (props) => {
  return <DemoShopstoryProvider>
    <ShopstoryMetadataProvider meta={props.meta}>
      <Shopstory content={props.content} />
    </ShopstoryMetadataProvider>
  </DemoShopstoryProvider>
}

Voila! Let's see our component in action:

Component types

There are 3 component types in Shopstory.

  • item (default) - available only in stacks inside of components

  • card - cards can be used in card grids or sliders.

  • section - full-screen section, can be added only at a root level of page

We haven't specified type property for our CustomComponent so it's treated as an item.

If you want to change a type of custom component just set type property in the component object:

export const shopstoryConfig: Config = {
    // ...
    components: [
      {
        id: "CustomComponent",
        label: "Custom component",
        type: "card"
        schema: [
          // ...
        ]
      }
    ]
}

Now the custom component should be available in a card picker.

Layout compatibility

When Shopstory renders a custom component it's always wrapped with a container div with display: grid set. So the resulting markup looks kind of like this:

<div style={{display: "grid"}}>
    <YourCustomComponent />
</div>

You should assume that the container div might vary in size (it's controlled by Shopstory layout, not you). Thanks to the display: grid your component will always fill the container div. It's your job to make your component adapt properly to different widths and heights. However, in most cases you don't need to do much.

Next steps

Last updated