Create a page-specific component

Introduction

Goal

Create a page-specific component with embedded content.

Prerequisites

Before starting:

To perform the Site Management API request in this tutorial it is recommended to use the Postman collection for the Site Management API. However, you can use any other method or tool you like such as the Site development app or curl or httpies.

Create the Image, Title, and Text field group type

Navigate to the Content app and from the dropdown in the top left, choose Content types.

Browse to the "Bloomreach (brxsaas)" namespace folder and from its context menu, choose New field group type.

In the New field group type dialog, enter "ImageTitleAndText" in the Name field, choose the 1 Column layout, and click OK.

In the content type editor, add the following three fields to the field group type:

Field TypePathRequiredDefault Caption
Image LinkimageImage
StringtitleTitle
Rich Text EditortextText

Click Done to save the field group type.

Define the ImageTitleAndText component using the Site Management API

Use the component endpoint to create a new "imagetitleandtext" component in the "brx-reference-spa" component group.

PUT https://<your-content-host>.bloomreach.io/management/site/v1/channels/<channel-branch>/component_groups/brx-reference-spa/components/imagetitleandtext

Use the following request body:

{
    "id": "brx-reference-spa/imagetitleandtext",
    "extends": "base/component",
    "hidden": false,
    "system": false,
    "xtype": null,
    "ctype": "ImageTitleAndText",
    "contentType": "brxsaas:ImageTitleAndText",
    "label": "Image, Title, and Text",
    "icon": null,
    "parameters": [
        {
            "name": "textalignment",
            "valueType": "string",
            "required": false,
            "hidden": false,
            "overlay": false,
            "defaultValue": "center",
            "displayName": null,
            "system": false,
            "config": {
                "value": [],
                "structuredValues": [
                  {
                    "key": "left",
                    "label": "Left"
                  },
                  {
                    "key": "center",
                    "label": "Center"
                  },
                  {
                    "key": "right",
                    "label": "Right"
                  }
                ],
                "valueListProvider": null,
                "sourceId": null,
                "type": "dropdown"
            }
        },
        {
            "name": "titlesize",
            "valueType": "string",
            "required": false,
            "hidden": false,
            "overlay": false,
            "defaultValue": "H3",
            "displayName": null,
            "system": false,
            "config": {
                "value": [
                    "H1",
                    "H2",
                    "H3",
                    "H4",
                    "H5"
                ],
                "structuredValues": [],
                "valueListProvider": null,
                "sourceId": null,
                "type": "dropdown"
            }
        }
    ],
    "fieldGroups": []
}

Note the following in the configuration above:

  • The "brx-reference-spa/imagetitleandtext" component extends the "base/component" component.
  • "contentType" is set to "brxsaas:ImageTitleAndText", the technical name for the field group type you defined. Content of this type will be embedded in the component instance and share its lifecycle with the component instance and the page it is on.
  • Two dropdown type parameters, "textalignment" and "titlesize", are defined to enable Site Editors some control over how the content is styled.

Implement the ImageTitleAndText React component

Create a folder components/ImageTitleAndText. The ImageTitleAndText component will live inside this folder.

Let's define some styles before implementing the component.

Create components/ImageTitleAndText/ImageTitleAndText.module.scss with the following contents:

.imagetitleandtext {
  display: inline-block;
  position: relative;
  width: 100%;
  
  img {
    max-width: 100%;
  }
  
  &__text {
    background: rgba(255, 255, 255, 0.3);
    padding: 20px;
    display: block;
    position: absolute;
    top: 0;
    left: 0;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    text-align: center;
  }
}

Next, create the actual ImageTitleAndText component in components/ImageTitleAndText/ImageTitleAndText.tsx:

import React from 'react';
import { Image } from 'react-bootstrap';
import { ImageSet, Reference, ContainerItem, getContainerItemContent } from '@bloomreach/spa-sdk';
import { BrProps } from '@bloomreach/react-sdk';

import styles from './ImageTitleAndText.module.scss';

interface ImageTitleAndTextCompound {
  image?: Reference;
  title?: string;
  text?: {
    value?: string;
  };
}

export function ImageTitleAndText({ component, page }: BrProps<ContainerItem>): React.ReactElement | null {
  if (component.isHidden()) {
    return page.isPreview() ? <div /> : null;
  }

  let imageRef;
  let title;
  let text;

  const content = getContainerItemContent<ImageTitleAndTextCompound>(component, page);
  if (content !== null) {
    imageRef = content.image;
    title = content.title;
    text = content.text?.value;
  }

  const { titlesize = 'H3', textalignment = 'center' } = component.getParameters();
  const image = imageRef && page?.getContent<ImageSet>(imageRef)?.getOriginal();

  return (
    <section className={`${styles.imagetitleandtext}`}>
      {image && (
        <Image src={image.getUrl()} alt={title} />
      )}
      <div className={`${styles.imagetitleandtext__text} text-${textalignment}`}>
        {titlesize === 'H1' && <h1 className="mb-2">{title}</h1>}
        {titlesize === 'H2' && <h2 className="mb-2">{title}</h2>}
        {titlesize === 'H3' && <h3 className="mb-2">{title}</h3>}
        {titlesize === 'H4' && <h4 className="mb-2">{title}</h4>}
        {titlesize === 'H5' && <h5 className="mb-2">{title}</h5>}
        {text && <div dangerouslySetInnerHTML={{ __html: page?.rewriteLinks(text) ?? '' }} />}
      </div>
    </section>
  );
}

Note the following about the component implementation:

  • The content embedded in the component instance is retrieved using the getContainerItemContent method.
  • The component does not render a manage content button; for page-specific components with embedded content, a content editor is automatically loaded in the component editor in the right sidebar in the Experience manager.

Export the ImageTitleAndText component in components/ImageTitleAndText/index.ts:

export { ImageTitleAndText } from './ImageTitleAndText';

Finally, add the required wiring to make the ImageTitleAndText component available in the application.

In components/index.tsx, add:

export * from './ImageTitleAndText';

In components/App.tsx, add ImageTitleAndText to the list of components imported from './components' as well as to the mapping in the App class.

import {
  ...
  ImageTitleAndText,
} from './components';
…
const MAPPING = {
  ...
  ImageTitleAndText,
};

You are now ready to test the ImageTitleAndText component.

Add the ImageTitleAndText component to the homepage

Open you channel in the Experience manager app and make sure your development project is selected.

Add the homepage to the project if you haven't done so already.

Open the left sidebar and click on the Components tab. The list of available components should include "Image, Title, and Text" in the Page-specific components section:

Click on "Image, Title, and Text" and add it to the container on the homepage.

Once added, click inside the component to open the right sidebar where the editing fields for the ImageTitleAndText field group type you defined should load on the Content tab.

Select an image and enter a title and some text. Click on Save to update the page preview.

Click on the Properties tab in the right sidebar to edit the style properties you defined for the component.

If everything works as expected, you completed this tutorial!