Your content creators can put all sorts of content in rich text elements. This is where most of your longer-form content lives, and it must be displayed correctly. Learn how to resolve Kontent.ai-specific entities, such as content items and components in rich text, so that your content always looks as intended.
What can go in the rich text?
When working in the Kontent.ai rich text editor, your content creators need the freedom to add various types of content. This spans native options such as formatted text structured with headings, lists, and tables to custom content specific to your project. For example, content such as disclaimers, tweets, or videos is something you define yourself.To add these kinds of custom content, content creators can insert either new components or existing content items within the rich text element. Then, based on the content types of the components or content items, your app can decide how to display them.The same goes for linking to other content items within the rich text element. Your app needs to decide how to resolve each link. For example, you might want to use specific routing logic for different types of content items.
Resolve inserted content items and components
Resolve content item links
Sign in with your Kontent.ai credentials or sign up for free to unlock the full lesson, track your progress, and access exclusive expert insights and tips!
When you retrieve content items using Delivery API, the rich text element values are stored as HTML5 fragments. To display rich text in the way you want, you convert the values to portable text using @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.
Structure-wise, content items and components are the same. You can create a component and a content item based on the same content type. The difference is in their scope.Components are always included in the API response because they’re an integral part of the rich text. However, if the rich text contains or links to any content items, these content items might not always be part of the API response.Use the same approach for all types of content you want to support in your rich text elements.
Links in rich text come in many flavors. Content creators can create links to assets, content items, telephone numbers, emails, and web URLs. For content item links, you need to define routing logic based on the content item’s content type.Here’s an example of how you can resolve links that point to content items for products.Use the same approach for links to other types of content items.
Rich text resolution in a nutshell
Expect the unexpectedRich text elements can be limited to contain content based on specific content types. As a result, if content creators insert or link to content items based on the wrong type, they get validation errors. This prevents them from publishing invalid content. However, they can still create invalid content while crafting their drafts.Make sure your app can safely deal with unknowns such as unexpected types of content. While published content is guaranteed to be valid, the latest content is not.
TSX
TSX
TSX
import { Elements } from "@kontent-ai/delivery-sdk";import { transformToPortableText } from "@kontent-ai/rich-text-resolver";import { PortableText, PortableTextReactResolvers } from "@kontent-ai/rich-text-resolver/utils/react";import { React } from "react";// Defines how to transform Kontent.ai-specific portable text components, as well as default blocksconst createRichTextResolver = (element: Elements.RichTextElement): PortableTextReactResolvers => ({ // The logic for individual portable text components is explained later in the lesson types: { // Resolution for components and content items inserted in rich text componentOrItem: 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 contentItemLink: 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 elementexport const RichTextComponent: React.FC<RichTextComponentProps> = (props) => { // Converts a Kontent.ai rich text element value to portable text const portableText = transformToPortableText(props.richTextElement.value); // 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-worldconst richTextElement: Elements.RichTextElement = response.data.item.elements.richtext;// Example: using 'RichTextComponent' to render your rich text<div> <RichTextComponent richTextElement={richTextElement} /></div>
import { Elements } from "@kontent-ai/delivery-sdk";import { PortableTextReactResolvers } from "@kontent-ai/rich-text-resolver/utils/react";import { React } from "react";import { CalloutComponent } from "../components/shared/richText/Callout";import { contentTypes } from "../models";const createRichTextResolver = (element: Elements.RichTextElement): PortableTextReactResolvers => ({ types: { // Components and content items inserted in rich text component: ({ value }) => { // 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.componentOrItem._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 { PortableTextReactResolvers } from "@kontent-ai/rich-text-resolver/utils/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 itemsconst 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): PortableTextReactResolvers => ({ marks: { // Links to content items contentItemLink: ({ value, // The linked item's metadata children, // Link text, which might be formatted }) => { // Gets content item link metadata from the response const link = element.links.find( (l) => l.linkId === value?.contentItemLink._ref ); return <ContentItemLink link={link!}>{children}</ContentItemLink>; }, },});