Skip to content

Rich text

A prose section. The renderer hands the saved Lexical document to Payload’s RichText (from @payloadcms/richtext-lexical/react) across the full width of the site’s container (containerClassName); the block adds no measure of its own.

There is no live preview on this page: the renderer needs @payloadcms/richtext-lexical, and loading it here would pull Payload into the docs bundle. For the same reason the renderer lives on its own entry, @bison-lab/payload-blocks/rich-text, so a site that does not use the block never loads Lexical either.

payload.config.ts / collections
import { RichTextBlock } from "@bison-lab/payload-blocks";
// In the collection's `blocks` array:
RichTextBlock
blocks/registry.ts
import { RichTextBlockRenderer } from "@bison-lab/payload-blocks/rich-text";
// In the site's registry:
richText: RichTextBlockRenderer,

The published page styles what the editor typed, so a heading reads as a heading. Every heading level takes the Theme heading font and its weights on the type scale (H1 text-4xl bold, H2 text-3xl bold, H3 text-2xl semibold, H4 text-xl semibold, H5 and H6 smaller). Paragraphs get space between them, bulleted and numbered lists their markers and indent, a quote a primary rule on its left, and links the primary color, underlined. Colors and fonts follow the Theme; there is nothing to configure.

The styles are Tailwind classes in the package’s dist, so the site’s stylesheet must scan it (@source "…/node_modules/@bison-lab/payload-blocks/dist"), as it already does for the other blocks.

Links in a rich text section go through linkComponent like every other link, the ones Lexical auto-detects included. One kind needs more: a link an editor makes to another document has no URL, only the document, and the route is the site’s to know. That is the same fact resolveLink carries, but Lexical hands the renderer a link node rather than a link row. The factory takes the site’s resolver, unpacks the node with internalDocToHrefFrom, and calls it, so the page path is defined once:

blocks/rich-text.tsx
"use client";
import { richTextBlockRenderer } from "@bison-lab/payload-blocks/rich-text";
import { resolveSiteLink } from "@/blocks/adapters";
export const SiteRichText = richTextBlockRenderer({ resolveLink: resolveSiteLink });

Register SiteRichText in place of RichTextBlockRenderer. It has to be built in a "use client" module: the rich text entry carries the client banner, so the factory is a client reference a Server Component can pass along but cannot call, and the resolver is a closure that could not cross the boundary as a prop.

A hand-written internalDocToHref still works, and wins if both options are passed. An unpopulated or unpublished document follows the resolver’s null rule and maps to #; there is no second unpublished policy. Without any resolver an internal link still renders through the adapter, at #, with a console error naming the option. A site whose editors link between documents should not ship that way.

An upload an editor drops into the prose goes through the same adapters: an image through imageComponent, any other file through linkComponent at its url. A bare id — an upload that has not resolved — renders nothing.

FieldTypeNotes
content *richText
settingsgroupLabelled “Block Settings”.
settings.backgroundselectLabelled “Background”. The surface this section sits on. Page is the plain page background. One of page, card, muted, color, gradient. Default "page".
settings.backgroundColortextLabelled “Color”.
settings.backgroundColorDarktextLabelled “Dark mode color”.
settings.gradientTotextLabelled “Gradient end”.
settings.gradientToDarktextLabelled “Dark mode gradient end”.
settings.gradientDirectiontextLabelled “Gradient direction”.
settings.spacingselectLabelled “Spacing”. The air above and below this section. Default is the block's own padding; Compact and Spacious replace it. This is the band, not the site-wide spacing in Theme → Appearance. One of compact, default, spacious. Default "default".
settings.anchortextLabelled “Anchor”. In-page links can target this section. Leave blank for none.
settings.hiddencheckboxLabelled “Hidden”. The section stays in the editor and is left off the page. Default false.

* required.

Answers in the FAQ columns block are plain text for the same reason: prose with links and lists belongs here.