# Components

## Register component in Shopstory config

Let's imagine the simplest possible component:

```typescript
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:

```typescript
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](https://docs.shopstory.app/schema-reference).

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

<figure><img src="https://1906827321-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F4j4BoYKV0GXMySXRws9n%2Fuploads%2Fe9LGyjC1qGzmShba8FFX%2FScreenshot%202022-11-30%20at%2014.23.20.png?alt=media&#x26;token=8e6ce297-084e-4dbc-951a-d3fb35eea1a8" alt=""><figcaption></figcaption></figure>

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:

```typescript
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`:

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

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

```typescript
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:

{% embed url="<https://vimeo.com/779558840>" %}

## 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:

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

Now the custom component should be available in a card picker.&#x20;

## 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:

```html
<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

* [Custom buttons](https://docs.shopstory.app/custom-code/buttons)
* [Connecting 3rd party resources](https://docs.shopstory.app/resources) (like products from e-commerce platforms, CMS entries, assets, etc) to component properties
* [Available schema property types](https://docs.shopstory.app/schema-reference)
