@kontent-ai/rich-text-resolver
.
Portable text serializes your rich text content into structured blocks. For each portable text block, you can specify what to do with them and how to render them.
This is useful for Kontent.ai-specific things such as content items and links to content items. But you can also specify how to resolve the more native parts of rich text such as headings, paragraphs, tables, and more.
The following code shows the building blocks of rich text resolution with React components.
import { Elements } from "@kontent-ai/delivery-sdk";
import { nodeParse, transformToPortableText, } from "@kontent-ai/rich-text-resolver";
import { PortableText, PortableTextComponents } from "@portabletext/react";
import { React } from "react";
// Defines how to transform Kontent.ai-specific portable text components, as well as default blocks
const createRichTextResolver = (element: Elements.RichTextElement): Partial<PortableTextComponents> => ({
// The logic for individual portable text components is explained later in the lesson
types: {
// Resolution for components and content items inserted in rich text
component: undefined,
// Resolution for tables in rich text
table: undefined,
// Resolution for assets in rich text
image: undefined,
},
marks: {
// Resolution for links to external URLs
link: undefined,
// Resolution for links to content items
internalLink: undefined,
},
block: {
// Examples of custom resolution for default blocks
h1: undefined, // h1 headings
p: undefined, // paragraphs
},
});
type RichTextComponentProps = {
richTextElement: Elements.RichTextElement;
};
// Custom React component that renders your rich text element
export const RichTextComponent: React.FC<RichTextComponentProps> = (props) => {
// Converts a Kontent.ai rich text element value to a JSON tree
const parsedTree = nodeParse(props.richTextElement.value);
// Converts the JSON tree to portable text
const portableText = transformToPortableText(parsedTree);
// Renders content based on the specified transformations
return (
<PortableText
value={portableText}
components={createRichTextResolver(props.richTextElement)}
/>
);
};
// In your application code, get a content item and retrieve its rich text element.
// Tip: Learn how to get content in https://kontent.ai/learn/develop/hello-world
const richTextElement: Elements.RichTextElement = response.data.item.elements.richtext;
// Example: using 'MyComponent' to render your rich text
<div>
<MyComponent value={richTextElement} />
</div>
import { Elements } from "@kontent-ai/delivery-sdk";
import { PortableTextComponent } from "@kontent-ai/rich-text-resolver";
import { PortableTextComponents, PortableTextTypeComponentProps, } from "@portabletext/react";
import { React } from 'react';
import { CalloutComponent } from "../components/shared/richText/Callout";
import { contentTypes } from "../models";
const createRichTextResolver = (element: Elements.RichTextElement): Partial<PortableTextComponents> => ({
types: {
// Components and content items inserted in rich text
component: ({
value,
}: PortableTextTypeComponentProps<PortableTextComponent>) => {
// Checks if the inserted content item is included in the response
// Kontent.ai components are always included in the response
const componentOrItem = element.linkedItems.find(
(i) => i.system.codename === value.component._ref
);
if (!componentOrItem) {
return (<div>The inserted content item wasn't found.</div>);
}
// Renders the component or content item based on its type
switch (componentOrItem.system.type) {
// Tip: Generate models at https://kontent.ai/learn/strongly-typed-models
case contentTypes.callout.codename:
return <CalloutComponent item={componentOrItem} />;
default:
return (<div>Content based on the type '{componentOrItem.system.type}' couldn't be resolved.</div>);
}
},
},
});
import { Elements, ILink } from "@kontent-ai/delivery-sdk";
import { PortableTextInternalLink } from "@kontent-ai/rich-text-resolver";
import { PortableTextComponents, PortableTextMarkComponentProps } from "@portabletext/react";
import { React, ReactNode } from "react";
import { ProductLink } from "../components";
import { contentTypes } from "../models";
type ContentItemLinkProps = {
link: ILink;
children: ReactNode;
};
// Custom React component for rendering links to content items
const ContentItemLink: React.FC<ContentItemLinkProps> = (props) => {
// Use different resolution logic based on the content type
switch (props.link.type) {
case contentTypes.product.codename:
return (
<ProductLink
itemCodename={props.link.codename}
urlSlug={props.link.urlSlug}
>
{props.children}
</ProductLink>
);
default:
return (<div>Link to the content item '{props.link.codename}' couldn't be resolved.</div>);
}
};
type ProductLinkProps = {};
const ProductLink: React.FC<ProductLinkProps> = (props) => {
// Based on your app routing, resolve links to products
};
const createRichTextResolver = (element: Elements.RichTextElement): Partial<PortableTextComponents> => ({
marks: {
// Links to content items
internalLink: ({
value, // The linked item's metadata
children, // Link text that might include text formatting
}: PortableTextMarkComponentProps<PortableTextInternalLink>) => {
// Gets content item link metadata from the response
const link = element.links.find(
(l) => l.linkId === value?.reference._ref
);
return <ContentItemLink link={link!}>{children}</ContentItemLink>;
},
},
});