Skip to main content

Block factories

COMET DXP offers factories for common block use cases.

BlocksBlock

The BlocksBlock factory is used to create a block that consists of multiple child blocks.

A BlocksBlock that supports rich text, image, and link list child blocks

API

page-content.block.ts
import { createBlocksBlock } from "@comet/blocks-api";

...

export const PageContentBlock = createBlocksBlock(
{
supportedBlocks: {
richtext: RichTextBlock,
image: DamImageBlock,
linkList: LinkListBlock,
},
},
"PageContent",
);

Admin

PageContentBlock.tsx
import { createBlocksBlock } from "@comet/blocks-admin";

...

export const PageContentBlock = createBlocksBlock({
name: "PageContent",
supportedBlocks: {
richtext: RichTextBlock,
image: DamImageBlock,
linkList: LinkListBlock,
},
});

Site

PageContentBlock.tsx
import { BlocksBlock, PropsWithData, SupportedBlocks } from "@comet/cms-site";
import { PageContentBlockData } from "@src/blocks.generated";

...

const supportedBlocks: SupportedBlocks = {
richtext: (props) => <RichTextBlock data={props} />,
image: (props) => <DamImageBlock data={props} />,
linkList: (props) => <LinkListBlock data={props} />,
};

export function PageContentBlock({ data }: PropsWithData<PageContentBlockData>) {
return <BlocksBlock data={data} supportedBlocks={supportedBlocks} />;
};

ListBlock

Similar to the BlocksBlock factory, the ListBlock factory is used to create a block that consists of multiple child blocks. The main difference is that the ListBlock factory only supports a single child block type.

A ListBlock based on a link block

API

link-list.block.ts
import { createListBlock } from "@comet/blocks-api";

...

export const LinkListBlock = createListBlock({ block: TextLinkBlock }, "LinkList");

Admin

LinkListBlock.tsx
import { createListBlock } from "@comet/blocks-admin";

...

export const LinkListBlock = createListBlock({
name: "LinkList",
block: TextLinkBlock,
});

Site

LinkListBlock.tsx
import { ListBlock, PropsWithData } from "@comet/cms-site";
import { LinkListBlockData } from "@src/blocks.generated";

...

export function LinkListBlock({ data }: PropsWithData<LinkListBlockData>) {
return <ListBlock data={data} block={(props) => <TextLinkBlock data={props} />} />;
}

ColumnsBlock

The ColumnsBlock factory is used to create a block that displays content in multiple columns. A ColumnsBlock may support different layouts for the same number of columns. For instance, two columns could be represented by three layouts: Same width, weighted left, weighted right.

A ColumnsBlock that supports single-column and two columns layouts

API

columns.block.ts
import { ColumnsBlockFactory, createBlocksBlock } from "@comet/blocks-api";

...

const ColumnsContentBlock = createBlocksBlock(
{
supportedBlocks: {
space: SpaceBlock,
richtext: RichTextBlock,
headline: HeadlineBlock,
image: DamImageBlock,
},
},
"ColumnsContent",
);

export const ColumnsBlock = ColumnsBlockFactory.create(
{
contentBlock: ColumnsContentBlock,
layouts: [{ name: "one-column" }, { name: "two-columns" }],
},
"Columns",
);

Admin

ColumnsBlock.tsx
import {
ColumnsLayoutPreview,
ColumnsLayoutPreviewContent,
ColumnsLayoutPreviewSpacing,
createBlocksBlock,
createColumnsBlock,
} from "@comet/blocks-admin";

...

const ColumnsContentBlock = createBlocksBlock({
name: "ColumnsContent",
supportedBlocks: {
space: SpaceBlock,
richtext: RichTextBlock,
headline: HeadlineBlock,
image: DamImageBlock,
},
});

export const ColumnsBlock = createColumnsBlock({
name: "Columns",
layouts: [
{
name: "one-column",
label: "One column",
columns: 1,
preview: (
<ColumnsLayoutPreview>
<ColumnsLayoutPreviewSpacing width={2} />
<ColumnsLayoutPreviewContent width={20} />
<ColumnsLayoutPreviewSpacing width={2} />
</ColumnsLayoutPreview>
),
},
{
name: "two-columns",
label: "Two columns",
columns: 2,
preview: (
<ColumnsLayoutPreview>
<ColumnsLayoutPreviewContent width={10} />
<ColumnsLayoutPreviewSpacing width={4} />
<ColumnsLayoutPreviewContent width={10} />
</ColumnsLayoutPreview>
),
},
],
contentBlock: ColumnsContentBlock,
});

Site

ColumnsBlock.tsx
import { BlocksBlock, PropsWithData, SupportedBlocks, withPreview } from "@comet/cms-site";
import { ColumnsBlockData, ColumnsContentBlockData } from "@src/blocks.generated";

...

const supportedBlocks: SupportedBlocks = {
space: (props) => <SpaceBlock data={props} />,
richtext: (props) => <RichTextBlock data={props} />,
headline: (props) => <HeadlineBlock data={props} />,
image: (props) => <DamImageBlock data={props} />,
};

function ColumnsContentBlock({ data }: PropsWithData<ColumnsContentBlockData>) {
return <BlocksBlock data={data} supportedBlocks={supportedBlocks} />;
};

export function ColumnsBlock({ data: { layout, columns } }: PropsWithData<ColumnsBlockData>) {
const Root = layout === "one-column" ? OneColumnRoot : TwoColumnRoot;
return (
<Root>
{columns.map((column) => (
<ColumnsContentBlock key={column.key} data={column.props} />
))}
</Root>
);
};

OneOfBlock

The OneOfBlock factory is used to create a block that can be one of several child blocks. Think of it as a switch or select.

A link block that is based on an OneOfBlock to support both internal and external links

API

link.block.ts
import { createOneOfBlock } from "@comet/blocks-api";

...

export const LinkBlock = createOneOfBlock(
{ supportedBlocks: { internal: InternalLinkBlock, external: ExternalLinkBlock, news: NewsLinkBlock }, allowEmpty: false },
"Link",
);

Admin

LinkBlock.tsx
import { createOneOfBlock } from "@comet/blocks-admin";

...

export const LinkBlock = createOneOfBlock({
supportedBlocks: { internal: InternalLinkBlock, external: ExternalLinkBlock, news: NewsLinkBlock },
});

Site

LinkBlock.tsx
import { OneOfBlock, PropsWithData, SupportedBlocks } from "@comet/cms-site";
import { LinkBlockData } from "@src/blocks.generated";

...

const supportedBlocks: SupportedBlocks = {
internal: ({ children, ...props }) => <InternalLinkBlock data={props}>{children}</InternalLinkBlock>,
external: ({ children, ...props }) => <ExternalLinkBlock data={props}>{children}</ExternalLinkBlock>,
news: ({ children, ...props }) => <NewsLinkBlock data={props}>{children}</NewsLinkBlock>,
};

interface LinkBlockProps extends PropsWithData<LinkBlockData> {
children: React.ReactElement;
}

export function LinkBlock({ data, children }: LinkBlockProps) {
return (
<OneOfBlock data={data} supportedBlocks={supportedBlocks}>
{children}
</OneOfBlock>
);
}

OptionalBlock

The OptionalBlock factory is used to make a block optional. Use it when some content is optional.

note

Prefer reacting to empty states (e.g., hiding a block when no image is selected) over using an OptionalBlock. Using an OptionalBlock adds additional complexity for users by requiring them to toggle the visibility.

A full-width image block with optional content using an OptionalBlock

API

optional-image.block.ts
import { createOptionalBlock } from "@comet/blocks-api";

...

export const OptionalImageBlock = createOptionalBlock(ImageBlock);

Admin

OptionalImageBlock.tsx
import { createOptionalBlock } from "@comet/blocks-admin";

...

export const OptionalImageBlock = createOptionalBlock(ImageBlock);

Site

LinkBlock.tsx
import { OptionalBlock, PropsWithData } from "@comet/cms-site";
import { OptionalImageBlockData } from "@src/blocks.generated";

...

export function OptionalImageBlock({ data }: PropsWithData<OptionalImageBlockData>) {
return (
<OptionalBlock
block={(props) => <ImageBlock data={props} />}
data={data}
/>
);
}

CompositeBlock (Admin only)

The CompositeBlock factory composes several child blocks and fields into a block. For most of your blocks, you will use this factory to create the block in the admin.

FullWidthImageBlock.tsx
import { createCompositeBlock } from "@comet/blocks-admin";

...

export const FullWidthImageBlock = createCompositeBlock({
name: "FullWidthImage",
displayName: <FormattedMessage id="cometDemo.blocks.fullWidthImage" defaultMessage="Full Width Image" />,
category: BlockCategory.Media,
blocks: {
image: {
block: DamImageBlock,
title: <FormattedMessage id="cometDemo.generic.image" defaultMessage="Image" />,
paper: true,
},
content: {
block: FullWidthImageContentBlock,
title: <FormattedMessage id="cometDemo.generic.content" defaultMessage="Content" />,
},
},
});