// Re-usable component typed against specific query results.
import {PortableText, type InferValue} from '@portabletext/react'
import {createImageUrlBuilder} from '@sanity/image-url'
import type {AuthorQueryResult, PostQueryResult} from './sanity.types'
type PortableTextValue = InferValue<PostQueryResult | AuthorQueryResult>
export function CustomPortableText(props: {value: PortableTextValue}) {
const builder = createImageUrlBuilder()
return (
<PortableText
components={{
types: {
image: ({value}) => {
const width = 1920
const height = 1080
return (
<img
src={builder
.image(value)
.width(width)
.height(height)
.fit('max')
.auto('format')
.url()}
alt={value.alt || ''}
loading="lazy"
height={height}
width={width}
/>
)
},
},
}}
value={props.value}
/>
)
}
// Strictly typed re-usable component that handles every Portable Text shape
// returned by registered queries. Relies on `overloadClientMethods` being
// enabled in `sanity.cli.ts#typegen` (the default).
import {type SanityQueries} from '@sanity/client'
import {createImageUrlBuilder} from '@sanity/image-url'
import {
PortableText,
type InferStrictComponents,
type InferValue,
} from '@portabletext/react'
type PortableTextValue = InferValue<SanityQueries[keyof SanityQueries]>
export function CustomPortableText(props: {value: PortableTextValue}) {
const builder = createImageUrlBuilder()
const components = {
types: {
image: ({value}) => {
const width = 1920
const height = 1080
return (
<img
src={builder
.image(value)
.width(width)
.height(height)
.fit('max')
.auto('format')
.url()}
alt={value.alt || ''}
loading="lazy"
height={height}
width={width}
/>
)
},
},
} satisfies InferStrictComponents<PortableTextValue>
return <PortableText components={components} value={props.value} />
}
Infer the Portable Text array value type from Sanity TypeGen generated types.
Useful when building a re-usable wrapper component that only takes
valueas an input prop and sets upcomponentsinternally. Pass a TypeGen- generated query result type that contains Portable Text fields - such as an individual query result likePostQueryResult, or theSanityQueriesinterface from@sanity/client- andInferValue<T>returns an array type containing every Portable Text item shape it can find.Always feed
InferValue<T>query result types, not Sanity schema types. Schema types describe how content is stored, which can differ from how it is queried (e.g. references resolved with->).