Knut Melvær
Knut is a principal developer marketing manager at Sanity.io
How to automatically generate linked headings with a custom serializer
import PortableText from "@sanity/block-content-to-react";
export const serializers = {
type: {
block: (props) => {
const { node, children } = props
const { style, _key } = node
if (/^h\d/.test(style)) {
const HeadingTag = style;
// Even though HTML5 allows id to start with a digit, we append it with a letter to avoid various JS methods to act up and make problems
const headingId = `h${_key}`;
return (
<HeadingTag id={headingId}>
<a
href={`#${headingId}`}
aria-hidden="true"
tabIndex={-1}
>#</a>
<span>{children}</span>
</HeadingTag>
)
}
// ... you can put in other overrides here
// or return the default ones 👇
return PortableText.defaultSerializers.types.block(props)
}
},
// more custom types here…
}This is a minimal example of how you can add extra attributes and markup to headings from Portable Text in React. You'd approach this similarly in other frameworks. Here we have a custom serializer for the block type. It looks after a style property that contains the pattern with the letter h and a digit (so h1, h2, h3, etc).
Then we generate an id from the _key that comes from the block data. This _key will be stable as long as the block (that is, the heading) exists. Alternatively, you can generate a readable id from the heading text data in children.
This markup put's a linked # inside of the heading, but you can of course do it however you want and add styling to it.
Knut is a principal developer marketing manager at Sanity.io
Automatically track when content was first published with a timestamp that sets once and never overwrites, providing reliable publication history for analytics and editorial workflows.
Go to First Published Timestamp FunctionAI-powered automatic tagging for Sanity blog posts that analyzes content to generate 3 relevant tags, maintaining consistency by reusing existing tags from your content library.
Go to Automatically tag blog postsThis can be used for blogs or articles where you want to possibly display next and previous article buttons
Go to Get current post, previous post, and next postMigration script to convert plain text to block content across your content lake
Go to Migrate plain text field to Portable Text