### Install @portabletext/react Source: https://github.com/portabletext/react-portabletext/blob/main/README.md Install the library using npm. This is the first step to using @portabletext/react in your project. ```bash npm install --save @portabletext/react ``` -------------------------------- ### Create Linkable Headers using Portable Text and Plain Text Conversion Source: https://github.com/portabletext/react-portabletext/blob/main/README.md Generate unique IDs for headers by combining `toPlainText()` with a slugification library. This example demonstrates how to create linkable `h2` elements by converting Portable Text block content to a slug for the `id` attribute. ```tsx import {PortableText, toPlainText, PortableTextComponents} import slugify from 'slugify' const LinkableHeader = ({children, value}) => { // `value` is the single Portable Text block of this header const slug = slugify(toPlainText(value)) return

{children}

} const components = { block: { h2: LinkableHeader, }, } satisfies PortableTextComponents ``` -------------------------------- ### Implement Custom Image Component for react-portabletext Source: https://github.com/portabletext/react-portabletext/blob/main/MIGRATING.md Provide a custom image component to render images when using react-portabletext. This example shows a barebones lazy-loaded image component using `@sanity/image-url` and `@sanity/asset-utils`. ```jsx import urlBuilder from '@sanity/image-url' import {getImageDimensions} from '@sanity/asset-utils' // Barebones lazy-loaded image component const SampleImageComponent = ({value}) => { const {width, height} = getImageDimensions(value) return ( {value.alt ) } // You'll now need to define your own image component ``` -------------------------------- ### Integrate CustomPortableText Component into a Page Source: https://github.com/portabletext/react-portabletext/blob/main/README.md Fetch Portable Text content using GROQ and render it using the `CustomPortableText` component. Ensure the fetched content is an array before passing it to the component. ```tsx import {createClient} from '@sanity/client' import {defineQuery} from 'groq' const client = createClient(...) export default async function Page({slug}: {slug: string}) { const postQuery = defineQuery(`*[_type == "post" && slug.current == $slug][0]{title,content}`) const data = await client.fetch(postQuery, {slug}) if (!data) return notFound() return (

{data.title}

{Array.isArray(data.content) && }
) } ``` -------------------------------- ### Import PortableText component Source: https://github.com/portabletext/react-portabletext/blob/main/MIGRATING.md Switch from default import of `BlockContent` to named import of `PortableText`. ```jsx // From: import BlockContent from '@sanity/block-content-to-react' // ✅ To: // Not the default export anymore import { PortableText } from '@portabletext/react' ``` -------------------------------- ### Customizing Marks (Em, Link, Highlight) Source: https://context7.com/portabletext/react-portabletext/llms.txt Override default rendering for text marks like 'em', 'link', and a custom 'highlight' mark. The 'link' mark demonstrates handling external URLs. ```tsx import { PortableText, type PortableTextComponents } from '@portabletext/react' const components: PortableTextComponents = { marks: { // Decorator override em: ({ children }) => ( {children} ), // Annotation: custom link with external target detection link: ({ value, children }) => { const isExternal = (value?.href || '').startsWith('http') return ( {children} ) }, // Custom annotation mark for highlighted text highlight: ({ value, children }) => ( {children} ), }, } export function RichText({ value }) { return } ``` -------------------------------- ### Convert Portable Text to Plain Text with `toPlainText()` Source: https://context7.com/portabletext/react-portabletext/llms.txt Utility function to convert Portable Text blocks into a plain string. Useful for meta tags, slugs, or search indexing where formatted output is not supported. ```tsx import { PortableText, toPlainText, type PortableTextComponents } from '@portabletext/react' import slugify from 'slugify' // Generate OG description from rich text export function PageMeta({ content }) { const description = toPlainText(content).slice(0, 155) return } ``` ```tsx import { PortableText, toPlainText, type PortableTextComponents } from '@portabletext/react' import slugify from 'slugify' // Generate anchor IDs for h2 blocks const components: PortableTextComponents = { block: { h2: ({ value, children }) => { const id = slugify(toPlainText(value), { lower: true, strict: true }) return

{children}

}, }, } export function Article({ content }) { return } ``` -------------------------------- ### Create a Reusable CustomPortableText Component Source: https://github.com/portabletext/react-portabletext/blob/main/README.md Define a `CustomPortableText` component that accepts Portable Text values and uses `InferStrictComponents` to ensure all schema types are handled. This component is ideal for consistent rendering across your application. ```tsx import type { SanityQueries} from '@sanity/client' import {createImageUrlBuilder} from '@sanity/image-url' import { PortableText, type InferStrictComponents, type InferValue, } from '@portabletext/react' const builder = createImageUrlBuilder(...) // Array value type for every Portable Text item shape across all registered queries. type PortableTextValue = InferValue export function CustomPortableText({value}: {value: PortableTextValue}) { const components = { types: { // `value` is fully typed from the inferred image variant. image: ({value}) => {value.alt, }, // Add `types`, `marks`, `block`, `list` etc. handlers as your schema requires. } satisfies InferStrictComponents // ^ TypeScript errors when the schema gains a custom type, block, mark, or list // style without a matching handler defined here. return } ``` -------------------------------- ### toPlainText() - Strip Formatting Source: https://context7.com/portabletext/react-portabletext/llms.txt A utility function to strip all formatting from Portable Text and return plain text. ```APIDOC ## toPlainText() ### Description Strips all formatting and structural elements from Portable Text content, returning a plain text string. ### Usage ```typescript import { toPlainText } from '@portabletext/react' const blocks = [ // ... Portable Text blocks ] const plainText = toPlainText(blocks) console.log(plainText) // Outputs the text content without any formatting ``` ### Parameters - **value** (Array | PortableTextBlock): The Portable Text content to process. ``` -------------------------------- ### Convert Portable Text to Plain Text with React Portable Text Source: https://github.com/portabletext/react-portabletext/blob/main/README.md Utilize the `toPlainText()` function to convert Portable Text blocks into a plain text string. This is useful for scenarios like generating meta descriptions or creating accessible text alternatives where formatting is not required or supported. ```tsx import {toPlainText} const MetaDescription = (myPortableTextData) => { return } ``` -------------------------------- ### Basic PortableText Usage in React Source: https://github.com/portabletext/react-portabletext/blob/main/README.md Render Portable Text content by passing an array of blocks to the PortableText component. Optionally, provide custom components for rendering. ```jsx import {PortableText} from '@portabletext/react' ``` -------------------------------- ### `toPlainText()` — strip all formatting Source: https://context7.com/portabletext/react-portabletext/llms.txt Utility function that converts one or more Portable Text blocks into a plain string. Useful for Open Graph meta tags, slug generation, text search indexing, or anywhere formatted output is not supported. ```APIDOC ## `toPlainText()` — strip all formatting ### Description Utility function that converts one or more Portable Text blocks into a plain string. Useful for Open Graph meta tags, slug generation, text search indexing, or anywhere formatted output is not supported. ### Usage **Generate OG description from rich text:** ```tsx import { PortableText, toPlainText, type PortableTextComponents } from '@portabletext/react' import slugify from 'slugify' export function PageMeta({ content }) { const description = toPlainText(content).slice(0, 155) return } ``` **Generate anchor IDs for h2 blocks:** ```tsx import { PortableText, toPlainText, type PortableTextComponents } from '@portabletext/react' import slugify from 'slugify' const components: PortableTextComponents = { block: { h2: ({ value, children }) => { const id = slugify(toPlainText(value), { lower: true, strict: true }) return

{children}

}, }, } export function Article({ content }) { return } ``` ``` -------------------------------- ### Advanced Portable Text Typing with Generics Source: https://github.com/portabletext/react-portabletext/blob/main/README.md Create custom, narrowed Portable Text types by specifying generics for marks, inline blocks, styles, and list types. This allows for precise typing of complex Portable Text structures. ```ts import {PortableTextBlock, PortableTextMarkDefinition, PortableTextSpan} from '@portabletext/types' // MARKS interface FirstMark extends PortableTextMarkDefinition { _type: 'firstMark' // ...other fields } interface SecondMark extends PortableTextMarkDefinition { _type: 'secondMark' // ...other fields } type CustomMarks = FirstMark | SecondMark // INLINE BLOCKS interface MyInlineBlock { _type: 'myInlineBlock' // ...other fields } type InlineBlocks = PortableTextSpan | MyInlineBlock // STYLES type TextStyles = 'normal' | 'h1' | 'myCustomStyle' // LISTS type ListStyles = 'bullet' | 'myCustomList' // CUSTOM PORTABLE TEXT BLOCK // Putting it all together by specifying generics // all of these are valid: // type CustomPortableTextBlock = PortableTextBlock // type CustomPortableTextBlock = PortableTextBlock // type CustomPortableTextBlock = PortableTextBlock type CustomPortableTextBlock = PortableTextBlock // Other BLOCKS that can appear inbetween text interface MyCustomBlock { _type: 'myCustomBlock' // ...other fields } // TYPE FOR PORTABLE TEXT FIELD ITEMS type PortableTextFieldType = CustomPortableTextBlock | MyCustomBlock // Using it in your document type interface MyDocumentType { portableTextField: PortableTextFieldType[] } ``` -------------------------------- ### Basic PortableText Usage Source: https://context7.com/portabletext/react-portabletext/llms.txt Minimal usage of the `` component with default rendering for block types. ```tsx import { PortableText } from '@portabletext/react' // Minimal usage — uses built-in defaults for all node types const blocks = [ { _type: 'block', _key: 'a1', style: 'normal', children: [{ _type: 'span', _key: 's1', text: 'Hello, world!', marks: [] }], markDefs: [], }, { _type: 'block', _key: 'a2', style: 'h2', children: [{ _type: 'span', _key: 's2', text: 'A heading', marks: [] }], markDefs: [], }, ] export function Article() { return (
{/* Renders:

Hello, world!

A heading

*/}
) } ``` -------------------------------- ### InferComponents for Flexible Component Handling Source: https://github.com/portabletext/react-portabletext/blob/main/README.md Use `InferComponents` when you need flexibility, such as during incremental migration or when dealing with frequently changing schemas. It allows optional handlers and permits extra handlers for types not present in the schema. ```tsx import {PortableText, type InferComponents} from '@portabletext/react' const components = { types: { image: ({value}) => {value.alt, // Optional: legacy types not in the current schema are allowed. }, } satisfies InferComponents ``` -------------------------------- ### Customizing PortableText Components Source: https://github.com/portabletext/react-portabletext/blob/main/README.md Define custom components for 'types' and 'marks' to control how specific Portable Text elements are rendered. Ensure referential identity for the components object for performance. ```jsx const myPortableTextComponents = { types: { image: ({value}) => , callToAction: ({value, isInline}) => isInline ? ( {value.text} ) : (
{value.text}
), }, marks: { link: ({children, value}) => { const rel = !value.href.startsWith('/') ? 'noreferrer noopener' : undefined return ( {children} ) }, }, } const YourComponent = (props) => { return } ``` -------------------------------- ### - Main Rendering Component Source: https://context7.com/portabletext/react-portabletext/llms.txt The primary export for rendering Portable Text. It accepts a `value` prop (Portable Text blocks), an optional `components` map for customization, and an optional `onMissingComponent` handler. It renders a React fragment. ```APIDOC ## Component ### Description Renders Portable Text blocks into React elements. It uses built-in defaults for standard node types and allows for extensive customization through the `components` prop. ### Usage ```tsx import { PortableText } from '@portabletext/react' const blocks = [ { _type: 'block', _key: 'a1', style: 'normal', children: [{ _type: 'span', _key: 's1', text: 'Hello, world!', marks: [] }], markDefs: [], }, { _type: 'block', _key: 'a2', style: 'h2', children: [{ _type: 'span', _key: 's2', text: 'A heading', marks: [] }], markDefs: [], }, ] export function Article() { return (
{/* Renders:

Hello, world!

A heading

*/}
) } ``` ### Props - **value** (Array | PortableTextBlock): The Portable Text content to render. - **components** (PortableTextComponents) - Optional: An object to override default rendering components for different Portable Text types and marks. - **onMissingComponent** (function) - Optional: A handler function called when a component for a specific type or mark is not found. ``` -------------------------------- ### `onMissingComponent` — missing component handler Source: https://context7.com/portabletext/react-portabletext/llms.txt Prop on `` that intercepts warnings for unregistered node types. Defaults to `console.warn`. Pass `false` to silence all warnings, or a function to route them to your own error tracking system. ```APIDOC ## `onMissingComponent` — missing component handler ### Description Prop on `` that intercepts warnings for unregistered node types. Defaults to `console.warn`. Pass `false` to silence all warnings, or a function to route them to your own error tracking system. ### Usage **Silence all warnings:** ```tsx import { PortableText } from '@portabletext/react' ``` **Send to an error tracker:** ```tsx import { PortableText } from '@portabletext/react' { // options.type — e.g. 'myCustomBlock' // options.nodeType — 'block' | 'mark' | 'blockStyle' | 'listStyle' | 'listItemStyle' Sentry.captureMessage(message, { level: 'warning', extra: { type: options.type, nodeType: options.nodeType }, }) }} /> ``` ``` -------------------------------- ### Handle Missing Components with `onMissingComponent` Source: https://context7.com/portabletext/react-portabletext/llms.txt Intercept warnings for unregistered node types in PortableText. Pass `false` to silence warnings or a function to route them to an error tracking system. ```tsx import { PortableText } from '@portabletext/react' // Silence all warnings ``` ```tsx import { PortableText } from '@portabletext/react' // Send to an error tracker { // options.type — e.g. 'myCustomBlock' // options.nodeType — 'block' | 'mark' | 'blockStyle' | 'listStyle' | 'listItemStyle' Sentry.captureMessage(message, { level: 'warning', extra: { type: options.type, nodeType: options.nodeType }, }) }} /> ``` -------------------------------- ### Custom List Components for Portable Text Source: https://github.com/portabletext/react-portabletext/blob/main/README.md Customizes the rendering of bulleted and numbered lists, and a custom 'checkmarks' list type. Applies margin classes for spacing. ```jsx const components = { list: { // Ex. 1: customizing common list types bullet: ({children}) =>
    {children}
, number: ({children}) =>
    {children}
, // Ex. 2: rendering custom lists checkmarks: ({children}) =>
    {children}
, }, } ``` -------------------------------- ### Custom Block Components for Portable Text Source: https://github.com/portabletext/react-portabletext/blob/main/README.md Customizes rendering for common block styles like 'normal', 'h1', and 'blockquote', as well as a custom 'customHeading' style. Uses Tailwind CSS classes for styling. ```tsx import {PortableText, PortableTextReactComponents} // `components` object you'll pass to PortableText const components = { block: { // Ex. 1: customizing common block types normal: ({children}) =>

{children}

, h1: ({children}) =>

{children}

, blockquote: ({children}) =>
{children}
, // Ex. 2: rendering custom styles customHeading: ({children}) => (

{children}

), }, } satisfies Partial ``` -------------------------------- ### InferStrictComponents for Production-Grade Renderers Source: https://github.com/portabletext/react-portabletext/blob/main/README.md Employ `InferStrictComponents` to enforce that your schema and renderer are in sync. It requires handlers for all inferred types and rejects handlers for keys not present in the schema, failing TypeScript compilation if there are discrepancies. ```tsx import {PortableText, type InferStrictComponents} from '@portabletext/react' const components = { types: { image: ({value}) => {value.alt, // Omit `image` and TypeScript errors. // Add `legacyEmbed` and TypeScript errors. }, } satisfies InferStrictComponents ``` -------------------------------- ### components.marks - Decorator and Annotation Marks Source: https://context7.com/portabletext/react-portabletext/llms.txt Customize the rendering of inline text marks, including decorators (like bold or italic) and annotations (like links). ```APIDOC ## components.marks ### Description Defines custom React components for rendering inline text marks. Decorator marks receive `children` and `markType`, while annotation marks also receive a `value` object containing their definition data. ### Usage ```tsx import { PortableText, type PortableTextComponents } from '@portabletext/react' const components: PortableTextComponents = { marks: { // Decorator override em: ({ children }) => ( {children} ), // Annotation: custom link with external target detection link: ({ value, children }) => { const isExternal = (value?.href || '').startsWith('http') return ( {children} ) }, // Custom annotation mark for highlighted text highlight: ({ value, children }) => ( {children} ), }, } export function RichText({ value }) { return } ``` ### Component Props - **children**: The content within the mark. - **value** (object) - For annotation marks: Contains the definition data for the mark (e.g., `href` for links). ``` -------------------------------- ### InferComponents vs InferStrictComponents for Component Maps Source: https://context7.com/portabletext/react-portabletext/llms.txt Use `InferComponents` for forgiving component maps where optional handlers are allowed. Use `InferStrictComponents` for strict typing, ensuring all custom handlers are defined and unknown handlers are rejected. ```tsx import { PortableText, type InferComponents, type InferStrictComponents } from '@portabletext/react' import { createClient } from '@sanity/client' import { defineQuery } from 'groq' const client = createClient({ projectId: 'abc123', dataset: 'production', apiVersion: '2024-01-01', useCdn: true }) // --- Forgiving: InferComponents --- export default async function BlogPage({ slug }: { slug: string }) { const query = defineQuery(`*[_type == "post" && slug.current == $slug][0]{title,content}`) const data = await client.fetch(query, { slug }) const components = { block: { h2: ({ children }) =>

{children}

, // Extra handlers for types not in this query are allowed }, } satisfies InferComponents return (

{data?.title}

{Array.isArray(data?.content) && }
) } // --- Strict: InferStrictComponents --- // Narrowed to specific query result types to keep the union tight import type { PostQueryResult, AuthorQueryResult } from './sanity.types' type Value = InferValue export function StrictPortableText({ value }: { value: Value }) { const components = { types: { image: ({ value }) => {value.alt, // Omit `image` → TypeScript error. Add `legacyEmbed` → TypeScript error. }, } satisfies InferStrictComponents return } ``` -------------------------------- ### Custom Mark Components for Portable Text Source: https://github.com/portabletext/react-portabletext/blob/main/README.md Defines custom renderers for emphasis (em) and link annotations. The `link` component handles external URLs by opening them in a new tab. ```tsx // `components` object you'll pass to PortableText w/ optional TS definition import {PortableTextComponents} const components = { marks: { // Ex. 1: custom renderer for the em / italics decorator em: ({children}) => {children}, // Ex. 2: rendering a custom `link` annotation link: ({value, children}) => { const target = (value?.href || '').startsWith('http') ? '_blank' : undefined return ( {children} ) }, }, } satisfies PortableTextComponents ``` -------------------------------- ### Basic Portable Text Typing with @portabletext/types Source: https://github.com/portabletext/react-portabletext/blob/main/README.md Use `PortableTextBlock` without generics for loosely typed Portable Text data when not using Sanity TypeGen. This provides default handling for basic block structures. ```ts import {PortableTextBlock} from '@portabletext/types' interface MySanityDocument { portableTextField: (PortableTextBlock | SomeBlockType)[] } ``` -------------------------------- ### Custom Image Component for Portable Text Source: https://github.com/portabletext/react-portabletext/blob/main/README.md Renders a custom image type, handling inline vs. block display and lazy loading. Requires `@sanity/image-url` and `@sanity/asset-utils` for image processing and dimension retrieval. ```jsx import {PortableText} from '@portabletext/react' import urlBuilder from '@sanity/image-url' import {getImageDimensions} from '@sanity/asset-utils' // Barebones lazy-loaded image component const SampleImageComponent = ({value, isInline}) => { const {width, height} = getImageDimensions(value) return ( {value.alt ) } const components = { types: { image: SampleImageComponent, // Any other custom types you have in your content // Examples: mapLocation, contactForm, code, featuredProjects, latestNews, etc. }, } const YourComponent = (props) => { return } ``` -------------------------------- ### Manually Typing PortableTextBlock with Generics Source: https://context7.com/portabletext/react-portabletext/llms.txt When not using Sanity TypeGen, use `PortableTextBlock` generics to manually define mark definitions, inline block shapes, block styles, and list item types for strict typing. ```ts import { PortableTextBlock, PortableTextMarkDefinition, PortableTextSpan, } from '@portabletext/types' // --- Mark definitions --- interface LinkMark extends PortableTextMarkDefinition { _type: 'link' href: string blank?: boolean } interface HighlightMark extends PortableTextMarkDefinition { _type: 'highlight' color: string } type CustomMarks = LinkMark | HighlightMark // --- Inline blocks --- interface InlineCode { _type: 'inlineCode' code: string language: string } type InlineBlocks = PortableTextSpan | InlineCode // --- Block styles and list types --- type TextStyles = 'normal' | 'h1' | 'h2' | 'h3' | 'blockquote' | 'lead' type ListStyles = 'bullet' | 'number' | 'checkmarks' // --- Fully narrowed block type --- type CustomBlock = PortableTextBlock // --- Custom block-level objects --- interface ImageBlock { _type: 'image' asset: { _ref: string; _type: 'reference' } alt?: string } // --- Final document field type --- type PortableTextField = CustomBlock | ImageBlock interface Post { _id: string title: string content: PortableTextField[] } ``` -------------------------------- ### Infer Portable Text Value Type using a Scoped Mock Query Source: https://github.com/portabletext/react-portabletext/blob/main/README.md Define a focused GROQ query for type generation purposes and use its result type with `InferValue`. This strategy keeps the type union tight without manual maintenance, but do not combine it with `SanityQueries[keyof SanityQueries]`. ```tsx import {type SanityQueries} from '@sanity/client' import {defineQuery} from 'groq' const mockQuery = defineQuery(`*[_type in ["author", "category", "post"]]{ _type == "author" => {bio}, _type == "category" => {description}, _type == "post" => {content}, }`) function CustomPortableText({value}: {value: InferValue}) { // ... } ``` -------------------------------- ### Custom List and List Item Renderers for React Portable Text Source: https://context7.com/portabletext/react-portabletext/llms.txt Maps list types (bullet, number, custom) and list item types to custom React components. Useful for styling different kinds of lists. ```tsx import { PortableText } from '@portabletext/react' const components = { list: { bullet: ({ children }) => (
    {children}
), number: ({ children }) => (
    {children}
), // Custom list type defined in Sanity schema checkmarks: ({ children }) => (
    {children}
), }, listItem: { bullet: ({ children }) =>
  • {children}
  • , number: ({ children }) =>
  • {children}
  • , checkmarks: ({ children }) =>
  • ✅ {children}
  • , }, } const blocks = [ { _type: 'block', _key: 'k1', listItem: 'bullet', level: 1, children: [{ _type: 'span', _key: 's1', text: 'First item', marks: [] }], markDefs: [] }, { _type: 'block', _key: 'k2', listItem: 'bullet', level: 1, children: [{ _type: 'span', _key: 's2', text: 'Second item', marks: [] }], markDefs: [] }, { _type: 'block', _key: 'k3', listItem: 'checkmarks', level: 1, children: [{ _type: 'span', _key: 's3', text: 'Done', marks: [] }], markDefs: [] }, ] export function Lists() { return } ``` -------------------------------- ### Rename 'blocks' prop to 'value' Source: https://github.com/portabletext/react-portabletext/blob/main/MIGRATING.md The main input prop for Portable Text content has been renamed from `blocks` to `value`. ```jsx // From: // ✅ To: ``` -------------------------------- ### Rename 'serializers' prop to 'components' Source: https://github.com/portabletext/react-portabletext/blob/main/MIGRATING.md The prop for custom renderers has been renamed from `serializers` to `components` to better reflect its role. ```jsx // From: // ✅ To: ``` -------------------------------- ### `mergeComponents()` — merge component maps Source: https://context7.com/portabletext/react-portabletext/llms.txt Utility that deep-merges a base `PortableTextReactComponents` object with a partial override map. The `block`, `list`, `listItem`, `marks`, and `types` keys are merged as objects; all other keys are replaced. Useful for building layered or theme-based component systems. ```APIDOC ## `mergeComponents()` — merge component maps ### Description Utility that deep-merges a base `PortableTextReactComponents` object with a partial override map. The `block`, `list`, `listItem`, `marks`, and `types` keys are merged as objects; all other keys are replaced. Useful for building layered or theme-based component systems. ### Usage **Merge brand components:** ```tsx import { defaultComponents, mergeComponents } from '@portabletext/react' const brandComponents = mergeComponents(defaultComponents, { block: { h1: ({ children }) =>

    {children}

    , h2: ({ children }) =>

    {children}

    , }, marks: { strong: ({ children }) => ( {children} ), }, }) ``` **Merge for a specific page section:** ```tsx import { defaultComponents, mergeComponents } from '@portabletext/react' const brandComponents = mergeComponents(defaultComponents, { block: { h1: ({ children }) =>

    {children}

    , h2: ({ children }) =>

    {children}

    , }, marks: { strong: ({ children }) => ( {children} ), }, }) // Later, merge again for a specific page section — h1/h2/strong overrides are preserved const darkSectionComponents = mergeComponents(brandComponents, { block: { normal: ({ children }) =>

    {children}

    , }, }) ``` ``` -------------------------------- ### Custom Block Style Renderers for React Portable Text Source: https://context7.com/portabletext/react-portabletext/llms.txt Maps block style values to custom React components. Useful for creating distinct visual styles for headings, quotes, and custom block types. ```tsx import { PortableText, type PortableTextReactComponents } from '@portabletext/react' import { toPlainText } from '@portabletext/react' import slugify from 'slugify' // Linkable header that generates an id from the block text const LinkableHeader = ({ children, value }) => { const slug = slugify(toPlainText(value), { lower: true }) return (

    {children}

    ) } const components: Partial = { block: { normal: ({ children }) =>

    {children}

    , h1: ({ children }) =>

    {children}

    , h2: LinkableHeader, h3: ({ children }) =>

    {children}

    , blockquote: ({ children }) => (
    {children}
    ), // Custom block style defined in your Sanity schema lead: ({ children }) => (

    {children}

    ), }, } export function Article({ value }) { return } ``` -------------------------------- ### Customize List Item Rendering in React Portable Text Source: https://github.com/portabletext/react-portabletext/blob/main/README.md Customize the rendering of different list item types (e.g., bulleted, checklist) by providing custom React components in the `listItem` object within the `components` prop. This allows for specific styling or content for each list item type. ```jsx const components = { listItem: { // Ex. 1: customizing common list types bullet: ({children}) =>
  • {children}
  • , // Ex. 2: rendering custom list items checkmarks: ({children}) =>
  • ✅ {children}
  • , }, } ``` -------------------------------- ### Fallback Components for Unknown Types in React Portable Text Source: https://context7.com/portabletext/react-portabletext/llms.txt Defines fallback components for unknown block types, marks, styles, lists, and list items. Useful for debugging or handling unexpected data structures. ```tsx import { PortableText } from '@portabletext/react' const components = { // Render unknown block types as a visible dev note in non-production unknownType: ({ value, isInline }) => { if (process.env.NODE_ENV === 'production') return null const Wrapper = isInline ? 'span' : 'div' return ( Unknown block type: {value._type} ) }, // Render unknown marks by passing through children unstyled unknownMark: ({ children }) => <>{children}, } ``` -------------------------------- ### components.types - Custom Block and Inline Object Types Source: https://context7.com/portabletext/react-portabletext/llms.txt Register custom React components for specific Portable Text `_type` fields, whether they appear as block-level objects or inline objects within text. ```APIDOC ## components.types ### Description Allows you to define custom React components for rendering specific Portable Text object types, distinguishing between block-level and inline objects. ### Usage ```tsx import { PortableText } from '@portabletext/react' import urlBuilder from '@sanity/image-url' import { getImageDimensions } from '@sanity/asset-utils' const imageBuilder = urlBuilder({ projectId: 'abc123', dataset: 'production' }) const SanityImage = ({ value, isInline }) => { const { width, height } = getImageDimensions(value) return ( {value.alt ) } const CallToAction = ({ value, isInline }) => isInline ? ( {value.text} ) : ( ) const components = { types: { image: SanityImage, callToAction: CallToAction, }, } export function Post({ portableTextValue }) { return } ``` ### Component Props - **value**: The Portable Text object data for the current node. - **isInline** (boolean): Indicates if the object is rendered inline within a text block. ``` -------------------------------- ### Infer Portable Text Value Type from All Registered Queries Source: https://github.com/portabletext/react-portabletext/blob/main/README.md Use `InferValue` to create a Portable Text value type that encompasses all possible Portable Text shapes from your registered Sanity queries. This is the preferred method for ensuring comprehensive type coverage. ```tsx import {type SanityQueries} from '@sanity/client' type PortableTextValue = InferValue ``` -------------------------------- ### Customizing Image and Call-to-Action Types Source: https://context7.com/portabletext/react-portabletext/llms.txt Register custom React components for 'image' and 'callToAction' Portable Text types. The `isInline` prop helps differentiate rendering contexts. ```tsx import { PortableText } from '@portabletext/react' import urlBuilder from '@sanity/image-url' import { getImageDimensions } from '@sanity/asset-utils' const imageBuilder = urlBuilder({ projectId: 'abc123', dataset: 'production' }) const SanityImage = ({ value, isInline }) => { const { width, height } = getImageDimensions(value) return ( {value.alt ) } const CallToAction = ({ value, isInline }) => isInline ? ( {value.text} ) : ( ) const components = { types: { image: SanityImage, callToAction: CallToAction, }, } export function Post({ portableTextValue }) { return } ``` -------------------------------- ### Customize individual block styles Source: https://github.com/portabletext/react-portabletext/blob/main/MIGRATING.md Easily override rendering for specific block styles like headings or custom styles using the `components.block` object. ```jsx // From: const BlockRenderer = (props) => { const {style = 'normal'} = props.node if (/^h\d/.test(style)) { const level = style.replace(/[^\d]/g, '') return React.createElement(style, {className: `heading-${level}`}, props.children) } if (style === 'blockquote') { return
    - {props.children}
    } // Fall back to default handling return BlockContent.defaultSerializers.types.block(props) } ; // ✅ To:

    {children}

    , // Same applies to custom styles customHeading: ({children}) => (

    {children}

    ), }, }} /> ``` -------------------------------- ### Infer Portable Text Value Type from Specific Named Queries Source: https://github.com/portabletext/react-portabletext/blob/main/README.md When `SanityQueries[keyof SanityQueries]` results in a large union type, narrow it down by providing a union of specific query result types (e.g., `AuthorQueryResult | PostQueryResult`) to `InferValue`. This requires manual synchronization as queries change. ```tsx import type {AuthorQueryResult, PostQueryResult} from './sanity.types' type PortableTextValue = InferValue ``` -------------------------------- ### Merge Component Maps with `mergeComponents()` Source: https://context7.com/portabletext/react-portabletext/llms.txt Deep-merges a base `PortableTextReactComponents` object with a partial override map. Useful for building layered or theme-based component systems. ```tsx import { defaultComponents, mergeComponents } from '@portabletext/react' const brandComponents = mergeComponents(defaultComponents, { block: { h1: ({ children }) =>

    {children}

    , h2: ({ children }) =>

    {children}

    , }, marks: { strong: ({ children }) => ( {children} ), }, }) ``` ```tsx import { defaultComponents, mergeComponents } from '@portabletext/react' const brandComponents = mergeComponents(defaultComponents, { block: { h1: ({ children }) =>

    {children}

    , h2: ({ children }) =>

    {children}

    , }, marks: { strong: ({ children }) => ( {children} ), }, }) // Later, merge again for a specific page section — h1/h2/strong overrides are preserved const darkSectionComponents = mergeComponents(brandComponents, { block: { normal: ({ children }) =>

    {children}

    , }, }) ``` -------------------------------- ### Disable Missing Component Warnings in React Portable Text Source: https://github.com/portabletext/react-portabletext/blob/main/README.md Control console warnings when Portable Text encounters an unknown component type. Set `onMissingComponent` to `false` to disable warnings entirely, or provide a custom function to handle these errors, such as reporting them to an error logging service. ```tsx import {PortableText} ``` ```tsx import {PortableText} { myErrorLogger.report(message, { // eg `someUnknownType` type: options.type, // 'block' | 'mark' | 'blockStyle' | 'listStyle' | 'listItemStyle' nodeType: options.nodeType }) }} /> ``` -------------------------------- ### Customizing Hard Break Rendering in React Portable Text Source: https://context7.com/portabletext/react-portabletext/llms.txt Controls how newline characters (`\n`) within text spans are rendered. Defaults to `
    `. Set to `false` to render the literal newline character. ```tsx import { PortableText } from '@portabletext/react' // Default — renders
    // Disable hard break rendering (render raw \n) // Custom hard break component , }} /> ```