Gathering detailed insights and metrics for @portabletext/react
Gathering detailed insights and metrics for @portabletext/react
Gathering detailed insights and metrics for @portabletext/react
Gathering detailed insights and metrics for @portabletext/react
npm install @portabletext/react
95.1
Supply Chain
99.6
Quality
88.6
Maintenance
100
Vulnerability
100
License
Module System
Min. Node Version
Typescript Support
Node Version
NPM Version
318 Stars
250 Commits
29 Forks
8 Watching
4 Branches
15 Contributors
Updated on 20 Nov 2024
TypeScript (99.79%)
Shell (0.21%)
Cumulative downloads
Total Downloads
Last day
-0.2%
39,093
Compared to previous day
Last week
13.3%
216,265
Compared to previous week
Last month
10%
871,860
Compared to previous month
Last year
48.6%
8,606,114
Compared to previous year
2
1
40
Render Portable Text with React.
Migrating from @sanity/block-content-to-react? Refer to the migration docs.
npm install --save @portabletext/react
1import {PortableText} from '@portabletext/react' 2 3<PortableText 4 value={[/* array of portable text blocks */]} 5 components={/* optional object of custom components to use */} 6/>
The rendered HTML does not have any styling applied, so you will either render a parent container with a class name you can target in your CSS, or pass custom components if you want to control the direct markup and CSS of each element.
Default components are provided for all standard features of the Portable Text spec, with logical HTML defaults. You can pass an object of components to use, both to override the defaults and to provide components for your custom content types.
Provided components will be merged with the defaults. In other words, you only need to provide the things you want to override.
Note: Make sure the object does not change on every render - eg do not create the object within a React component, or if you do, use useMemo
to ensure referential identity between renders for better performance.
1const myPortableTextComponents = { 2 types: { 3 image: ({value}) => <img src={value.imageUrl} />, 4 callToAction: ({value, isInline}) => 5 isInline ? ( 6 <a href={value.url}>{value.text}</a> 7 ) : ( 8 <div className="callToAction">{value.text}</div> 9 ), 10 }, 11 12 marks: { 13 link: ({children, value}) => { 14 const rel = !value.href.startsWith('/') ? 'noreferrer noopener' : undefined 15 return ( 16 <a href={value.href} rel={rel}> 17 {children} 18 </a> 19 ) 20 }, 21 }, 22} 23 24const YourComponent = (props) => { 25 return <PortableText value={props.value} components={myPortableTextComponents} /> 26}
These are the overridable/implementable keys:
types
An object of React components that renders different types of objects that might appear both as part of the input array, or as inline objects within text blocks - eg alongside text spans.
Use the isInline
property to check whether or not this is an inline object or a block.
The object has the shape {typeName: ReactComponent}
, where typeName
is the value set in individual _type
attributes.
Example of rendering a custom image
object:
1import {PortableText} from '@portabletext/react' 2import urlBuilder from '@sanity/image-url' 3import {getImageDimensions} from '@sanity/asset-utils' 4 5// Barebones lazy-loaded image component 6const SampleImageComponent = ({value, isInline}) => { 7 const {width, height} = getImageDimensions(value) 8 return ( 9 <img 10 src={urlBuilder() 11 .image(value) 12 .width(isInline ? 100 : 800) 13 .fit('max') 14 .auto('format') 15 .url()} 16 alt={value.alt || ' '} 17 loading="lazy" 18 style={{ 19 // Display alongside text if image appears inside a block text span 20 display: isInline ? 'inline-block' : 'block', 21 22 // Avoid jumping around with aspect-ratio CSS property 23 aspectRatio: width / height, 24 }} 25 /> 26 ) 27} 28 29const components = { 30 types: { 31 image: SampleImageComponent, 32 // Any other custom types you have in your content 33 // Examples: mapLocation, contactForm, code, featuredProjects, latestNews, etc. 34 }, 35} 36 37const YourComponent = (props) => { 38 return <PortableText value={somePortableTextInput} components={components} /> 39}
marks
Object of React components that renders different types of marks that might appear in spans. Marks can either be simple "decorators" (eg emphasis, underline, italic) or full "annotations" which include associated data (eg links, references, descriptions).
If the mark is a decorator, the component will receive a markType
prop which has the name of the decorator (eg em
). If the mark is an annotation, it will receive both a markType
with the associated _type
property (eg link
), and a value
property with an object holding the data for this mark.
The component also receives a children
prop that should (usually) be returned in whatever parent container component makes sense for this mark (eg <a>
, <em>
).
1// `components` object you'll pass to PortableText w/ optional TS definition 2import {PortableTextComponents} from '@portabletext/react' 3 4const components: PortableTextComponents = { 5 marks: { 6 // Ex. 1: custom renderer for the em / italics decorator 7 em: ({children}) => <em className="text-gray-600 font-semibold">{children}</em>, 8 9 // Ex. 2: rendering a custom `link` annotation 10 link: ({value, children}) => { 11 const target = (value?.href || '').startsWith('http') ? '_blank' : undefined 12 return ( 13 <a href={value?.href} target={target} rel={target === '_blank' && 'noindex nofollow'}> 14 {children} 15 </a> 16 ) 17 }, 18 }, 19}
block
An object of React components that renders portable text blocks with different style
properties. The object has the shape {styleName: ReactComponent}
, where styleName
is the value set in individual style
attributes on blocks (normal
being the default).
1// `components` object you'll pass to PortableText 2const components = { 3 block: { 4 // Ex. 1: customizing common block types 5 h1: ({children}) => <h1 className="text-2xl">{children}</h1>, 6 blockquote: ({children}) => <blockquote className="border-l-purple-500">{children}</blockquote>, 7 8 // Ex. 2: rendering custom styles 9 customHeading: ({children}) => ( 10 <h2 className="text-lg text-primary text-purple-700">{children}</h2> 11 ), 12 }, 13}
The block
object can also be set to a single React component, which would handle block styles of any type.
list
Object of React components used to render lists of different types (bullet
vs number
, for instance, which by default is <ul>
and <ol>
, respectively).
Note that there is no actual "list" node type in the Portable Text specification, but a series of list item blocks with the same level
and listItem
properties will be grouped into a virtual one inside of this library.
1const components = { 2 list: { 3 // Ex. 1: customizing common list types 4 bullet: ({children}) => <ul className="mt-xl">{children}</ul>, 5 number: ({children}) => <ol className="mt-lg">{children}</ol>, 6 7 // Ex. 2: rendering custom lists 8 checkmarks: ({children}) => <ol className="m-auto text-lg">{children}</ol>, 9 }, 10}
The list
property can also be set to a single React component, which would handle lists of any type.
listItem
Object of React components used to render different list item styles. The object has the shape {listItemType: ReactComponent}
, where listItemType
is the value set in individual listItem
attributes on blocks.
1const components = { 2 listItem: { 3 // Ex. 1: customizing common list types 4 bullet: ({children}) => <li style={{listStyleType: 'disclosure-closed'}}>{children}</li>, 5 6 // Ex. 2: rendering custom list items 7 checkmarks: ({children}) => <li>✅ {children}</li>, 8 }, 9}
The listItem
property can also be set to a single React component, which would handle list items of any type.
hardBreak
Component to use for rendering "hard breaks", eg \n
inside of text spans.
Will by default render a <br />
. Pass false
to render as-is (\n
)
unknownMark
React component used when encountering a mark type there is no registered component for in the components.marks
prop.
unknownType
React component used when encountering an object type there is no registered component for in the components.types
prop.
unknownBlockStyle
React component used when encountering a block style there is no registered component for in the components.block
prop. Only used if components.block
is an object.
unknownList
React component used when encountering a list style there is no registered component for in the components.list
prop. Only used if components.list
is an object.
unknownListItem
React component used when encountering a list item style there is no registered component for in the components.listItem
prop. Only used if components.listItem
is an object.
When the library encounters a block, mark, list or list item with a type that is not known (eg it has no corresponding component in the components
property), it will by default print a console warning.
To disable this behavior, you can either pass false
to the onMissingComponent
property, or give it a custom function you want to use to report the error. For instance:
1import {PortableText} from '@portabletext/react' 2 3<PortableText 4 value={[/* array of portable text blocks */]} 5 onMissingComponent={false} 6/> 7 8// or, pass it a function: 9 10<PortableText 11 value={[/* array of portable text blocks */]} 12 onMissingComponent={(message, options) => { 13 myErrorLogger.report(message, { 14 // eg `someUnknownType` 15 type: options.type, 16 17 // 'block' | 'mark' | 'blockStyle' | 'listStyle' | 'listItemStyle' 18 nodeType: options.nodeType 19 }) 20 }} 21/>
This module also exports a function (toPlainText()
) that will render one or more Portable Text blocks as plain text. This is helpful in cases where formatted text is not supported, or you need to process the raw text value.
For instance, to render an OpenGraph meta description for a page:
1import {toPlainText} from '@portabletext/react' 2 3const MetaDescription = (myPortableTextData) => { 4 return <meta name="og:description" value={toPlainText(myPortableTextData)} /> 5}
Or to generate element IDs for headers, in order for them to be linkable:
1import {PortableText, toPlainText, PortableTextComponents} from '@portabletext/react' 2import slugify from 'slugify' 3 4const LinkableHeader = ({children, value}) => { 5 // `value` is the single Portable Text block of this header 6 const slug = slugify(toPlainText(value)) 7 return <h2 id={slug}>{children}</h2> 8} 9 10const components: PortableTextComponents = { 11 block: { 12 h2: LinkableHeader, 13 }, 14}
Portable Text data can be typed using the @portabletext/types
package.
Use PortableTextBlock
without generics for loosely typed defaults.
1import {PortableTextBlock} from '@portabletext/types' 2 3interface MySanityDocument { 4 portableTextField: (PortableTextBlock | SomeBlockType)[] 5}
PortableTextBlock
supports generics, and has the following signature:
1interface PortableTextBlock< 2 M extends PortableTextMarkDefinition = PortableTextMarkDefinition, 3 C extends TypedObject = ArbitraryTypedObject | PortableTextSpan, 4 S extends string = PortableTextBlockStyle, 5 L extends string = PortableTextListItemType, 6> {}
Create your own, narrowed Portable text type:
1import {PortableTextBlock, PortableTextMarkDefinition, PortableTextSpan} from '@portabletext/types' 2 3// MARKS 4interface FirstMark extends PortableTextMarkDefinition { 5 _type: 'firstMark' 6 // ...other fields 7} 8 9interface SecondMark extends PortableTextMarkDefinition { 10 _type: 'secondMark' 11 // ...other fields 12} 13 14type CustomMarks = FirstMark | SecondMark 15 16// INLINE BLOCKS 17 18interface MyInlineBlock { 19 _type: 'myInlineBlock' 20 // ...other fields 21} 22 23type InlineBlocks = PortableTextSpan | MyInlineBlock 24 25// STYLES 26 27type TextStyles = 'normal' | 'h1' | 'myCustomStyle' 28 29// LISTS 30 31type ListStyles = 'bullet' | 'myCustomList' 32 33// CUSTOM PORTABLE TEXT BLOCK 34 35// Putting it all together by specifying generics 36// all of these are valid: 37// type CustomPortableTextBlock = PortableTextBlock<CustomMarks> 38// type CustomPortableTextBlock = PortableTextBlock<CustomMarks, InlineBlocks> 39// type CustomPortableTextBlock = PortableTextBlock<CustomMarks, InlineBlocks, TextStyles> 40type CustomPortableTextBlock = PortableTextBlock<CustomMarks, InlineBlocks, TextStyles, ListStyles> 41 42// Other BLOCKS that can appear inbetween text 43 44interface MyCustomBlock { 45 _type: 'myCustomBlock' 46 // ...other fields 47} 48 49// TYPE FOR PORTABLE TEXT FIELD ITEMS 50type PortableTextFieldType = CustomPortableTextBlock | MyCustomBlock 51 52// Using it in your document type 53interface MyDocumentType { 54 portableTextField: PortableTextFieldType[] 55}
MIT © Sanity.io
No vulnerabilities found.
No security vulnerabilities found.