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.
API
import { createBlocksBlock } from "@comet/blocks-api";
...
export const PageContentBlock = createBlocksBlock(
{
supportedBlocks: {
richtext: RichTextBlock,
image: DamImageBlock,
linkList: LinkListBlock,
},
},
"PageContent",
);
Admin
import { createBlocksBlock } from "@comet/blocks-admin";
...
export const PageContentBlock = createBlocksBlock({
name: "PageContent",
supportedBlocks: {
richtext: RichTextBlock,
image: DamImageBlock,
linkList: LinkListBlock,
},
});
Site
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.
API
import { createListBlock } from "@comet/blocks-api";
...
export const LinkListBlock = createListBlock({ block: TextLinkBlock }, "LinkList");
Admin
import { createListBlock } from "@comet/blocks-admin";
...
export const LinkListBlock = createListBlock({
name: "LinkList",
block: TextLinkBlock,
});
Site
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.
API
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
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
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.
API
import { createOneOfBlock } from "@comet/blocks-api";
...
export const LinkBlock = createOneOfBlock(
{ supportedBlocks: { internal: InternalLinkBlock, external: ExternalLinkBlock, news: NewsLinkBlock }, allowEmpty: false },
"Link",
);
Admin
import { createOneOfBlock } from "@comet/blocks-admin";
...
export const LinkBlock = createOneOfBlock({
supportedBlocks: { internal: InternalLinkBlock, external: ExternalLinkBlock, news: NewsLinkBlock },
});
Site
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.
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.
API
import { createOptionalBlock } from "@comet/blocks-api";
...
export const OptionalImageBlock = createOptionalBlock(ImageBlock);
Admin
import { createOptionalBlock } from "@comet/blocks-admin";
...
export const OptionalImageBlock = createOptionalBlock(ImageBlock);
Site
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.
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" />,
},
},
});