Vue Storefront is now Alokai! Learn More
Creating CMS components

Creating CMS components

This guide will show you how you could approach adding new components to your Alokai & CMS setup. The described steps will also come in handy while editing the existing components.

Creating a frontend component

In this section, you're going to create a basic frontend Picture component that displays an image and its caption. The content for the component will be dynamic and delivered by a CMS.

Picture component

Code examples in this guide refer to the /apps/storefront-unified-nextjs directory of your Next Storefront.

1

Create a component

Create a new picture.tsx file with the following content:

components/cms/page/example.tsx
import { PropsWithStyle } from '@storefront-ui/react';
import { AgnosticCmsImage } from '@vsf-enterprise/cms-components-utils';
import classNames from 'classnames';
import { PropsWithChildren, ReactNode } from 'react';

export interface PictureProps extends PropsWithStyle, PropsWithChildren {
  caption: ReactNode;
  image?: AgnosticCmsImage;
}

export default function Picture({ children, caption = children, className, image, ...rest }: PictureProps) {
  const { alt, desktop, mobile } = image ?? {};

  return (
    <figure className={classNames('flex flex-col items-center', className)} {...rest}>
      {image && (
        <picture>
          {mobile && <source media="(max-width: 768px)" srcSet={mobile} />}
          {desktop && <img alt={alt} className="rounded-md" src={desktop} />}
        </picture>
      )}
      {caption && <figcaption className="text-center">{caption}</figcaption>}
    </figure>
  );
}

2

Register the component

If you are using our Builder.io integration, you have to register the Custom Component in the schemas.tsx file:

sf-modules/cms-builderio/components/schemas.tsx
import { RegisteredComponent } from '@builder.io/sdk-react';
import Picture from '@/components/cms/page/picture'; 
export const customComponents: RegisteredComponent[] = [
  // ... other components schemas
  {
    component: Picture,
    defaultChildren: [
      {
        '@type': '@builder.io/sdk:Element',
        component: {
          name: 'Editorial',
          options: {
            content: 'Image caption',
          },
        },
      },
    ],
    image: 'https://alokai.com/favicon.svg',
    inputs: [
      {
        ...baseImageInput,
        name: 'image',
        required: true,
      },
    ],
    name: 'Picture',
  },
];

If you are using our other integrations, import the component in the render-cms-content.tsx wrapper:

sf-modules/cms-<name>/components/render-cms-content.tsx
import type { ComponentType } from 'react';
import Picture from '@/components/cms/page/picture'; 
const components: Record<string, CmsComponent> = {
  // ... other components
  Picture, };

Creating a CMS component

The process of creating a structure for a custom component differs in every CMS. Select your platform from the tabs below and follow the associated guide.

In this section, you're going to create a new, custom Content Type in Amplience. It will act as a scaffolding for entries which will be rendered by your new frontend component. Remember that by default you'll be equipped with couple predefined Alokai components (content models/types).

Read more about creating Content Types in the Amplience documentation.

1

Create Content Type

Open up your Amplience Dynamic Content panel, navigate to the Development dropdown and choose Content Type schemas. Once a popup appears on the screen, choose "code from scratch".

In the following screen, give your schema an id (in the URI format, e.g. https://www.vuestorefront.io/picture.json) and set Content Type as the validation level. Hit the Create schema button to confirm.

Schema from scratch modal

A schema editor window should pop up. Now you can create your own schema based on pre-configured properties listed in add property dropdown.

2

Add the component field

In the schema, add the component field of type string. It is mandatory for all Content Types which act as components (e.g. Banner, Hero). Its value should represent the name of the frontend component which will be used to render it.

Use the const property to hardcode that value so that content editors do not have to type it manually every time they create a new Picture entry.

{
  "properties": {
    "component": {
      "title": "Component",
      "type": "string",
      "const": "Picture"
    }
  }
}

3

Add image field

You can add any field you want, for our Picture Content Type we will need a image field.

{
  "properties": {
    "image": {
      "type": "object",
      "allOf": [
        {
          "$ref": "http://bigcontent.io/cms/schema/v1/core#/definitions/image-link"
        }
      ]
    }
  }
}

If you want to make the field localizable, it has to be wrapped in the localized-value. For instance the localized image would look as follows:

{
  "properties": {
    "image": {
            "allOf":[
                {
                    "$ref":"http://bigcontent.io/cms/schema/v1/core#/definitions/localized-value"
                }
            ],
            "properties": {
                "values": {
                    "items": {
                        "properties": {
                            "value": {
                                "title": "Image",
                                "allOf": [
                                    { "$ref": "http://bigcontent.io/cms/schema/v1/core#/definitions/image-link" }
                                ]
                            }
                        }
                    }
                }
            }
        },
  }
}

You can read more about the localization in the Amplience docs. We recommend also to analyze the schema for the Alokai's content types which we provide out of the box for you. You can find them in apps/storefront-middleware/sf-modules/cms-amplience/content-type-schemas/schemas directory.

4

To make the caption flexible, we can set a caption as Editorial Content Type, which will allow you to use rich text features. Create the caption field of type content-link. As the only possible type to be chosen pick the https://www.vuestorefront.io/editorial.json schema which allows you to add rich text.

{
  "properties": {
    "caption": {
      "type": "object",
      "allOf": [
        {
          "$ref": "http://bigcontent.io/cms/schema/v1/core#/definitions/content-link"
        },
        {
          "properties": {
            "contentType": {
              "enum": ["https://www.vuestorefront.io/editorial.json"]
            }
          }
        }
      ]
    }
  }
}

It is worth to mention that you can share different kind of references between schemas as described here.

5

Make the component stylable

Additionally, you can make your component stylable by adding another field of type Content link to it. Name it styles and let it only accept schema of the styles (https://www.alokai.com/styles_partial.json).

{
  "properties": {
    "styles": {
      "type": "array",
      "items": {
        "type": "object",
        "allOf": [
          {
            "$ref": "https://www.alokai.com/styles_partial.json#/definitions/styles"
          }
        ]
      }
    }
  }
}

styles field has to be of type array to allow setting multiple styles based on media queries.

Once done, save your Picture Content Type schema. Now it should look like this:

{
  "$id": "https://www.vuestorefront.io/picture.json",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "allOf": [
    {
      "$ref": "http://bigcontent.io/cms/schema/v1/core#/definitions/content"
    }
  ],
  "title": "Picture",
  "description": "Picture Content Type schema",
  "type": "object",
  "properties": {
    "component": {
      "const": "Picture",
      "title": "Component",
      "type": "string"
    },
    "image": {
      "type": "object",
      "allOf": [
        {
          "$ref": "http://bigcontent.io/cms/schema/v1/core#/definitions/image-link"
        }
      ]
    },
    "caption": {
      "type": "object",
      "allOf": [
        {
          "$ref": "http://bigcontent.io/cms/schema/v1/core#/definitions/content-link"
        },
        {
          "properties": {
            "contentType": {
              "enum": ["https://www.vuestorefront.io/editorial.json"]
            }
          }
        }
      ]
    },
    "styles": {
      "items": {
        "allOf": [
          {
            "$ref": "https://www.vuestorefront.io/styles_partial.json#/definitions/styles"
          }
        ],
        "type": "object"
      },
      "type": "array"
    }
  }
}

6

Register schema

In order to use your schema, it needs to be registered, so click on the Save and register as content type option from Save dropdown in upper right corner of the screen.

Save Content type schema

In the following screen set the Content type label to Picture and set associated repository to Content. Optionally you can also add the icon and card for better recognition of the Content Type for final users.

7

Add Visualization

To be able to preview the Picture Content Type, go to the Visualizations tab and create a new visualization. Our module provides a /amplience-visualization Storefront route which allows you to preview a single component in isolation. We can use this page to set up the Localhost visualization. To to identify the component, make sure that the tokens are passed as query params, so the Visualization URL should look like this http://localhost:3000/amplience-visualization?hubName={{hub.name}}&contentItemId={{content.sys.id}}&deliveryKey={{delivery.key}}&snapshotId={{snapshot.id}}&vseDomain={{vse.domain}}&locales={{locales}}.

Localhost visualization

Once done, click the Save button to confirm.

You can read more about the Amplience visualizations in the official documentation.

Register the new component in the Page

To be able to use the new Picture component in the Page Content Type, you need to include it in the componentsAboveFold and componentsBelowFold fields.

Go to Development > Content Type schemas and search for the Page Content Type schema (https://www.vuestorefront.io/page.json). Open it in the editor and scroll down to the properties section. Include the ID of your Picture component in both componentsAboveFold and componentsBelowFold.

{
  "properties": {
    "componentsAboveFold": {
      "items": {
        "allOf": [
          {
            "$ref": "http://bigcontent.io/cms/schema/v1/core#/definitions/content-link"
          },
          {
            "properties": {
              "contentType": {
                "enum": [
                  "https://www.vuestorefront.io/picture.json"                ]
              }
            }
          }
        ]
      }
    },
    "componentsBelowFold": {
      "items": {
        "allOf": [
          {
            "$ref": "http://bigcontent.io/cms/schema/v1/core#/definitions/content-link"
          },
          {
            "properties": {
              "contentType": {
                "enum": [
                  "https://www.vuestorefront.io/picture.json"                ]
              }
            }
          }
        ]
      }
    }
  }
}

As a last step, click the blue dropdown arrow in the top-right corner and choose Save and sync Content Type option from the list.

8

Create a new entry

Now you can create a new entry based on the Picture Content Type. Go to the Content tab and click the Create content button. Choose the Picture Content Type from the list and fill in the fields with the desired values. Once done, click the Save button to confirm. After that, the visualization of the new entry should appear on the right side of the screen.

Create new entry

Read also

Congratulations! You've just created your first CMS component. Now it's time you added it to a page that can be rendered by your Storefront. Follow the guide on Creating CMS pages to see how it's done or read our other guides.