
Code Snippets with @sanity/code-input and Prism React Renderer
- Sanity
- Next.js
Contents
As developers and content creators, we all know the importance of clearly presenting code snippets. They’re not just chunks of text but a gateway to better understanding and engagement. While the foundational work by dwe.fi and Bjørge Næss has paved the way, it’s time to embrace the updates that make code representation in Sanity even better.
I will be showing off how to get it setup in your Next.js and Sanity project, but the information below can still be used a reference to implement it else where.
What’s New in @sanity/code-input
Since its introduction, @sanity/code-input
has undergone several updates. It includes switching over to CodeMirror as the code editor from the previous AceEditor and a different way to highlight lines.
Installation and Setup
Installing @sanity/code-input
Start by adding the plugin to your project:
1yarn add @sanity/code-input
Add to your config file
sanity.config.ts
1import { defineConfig } from 'sanity';2import { codeInput } from '@sanity/code-input';34export default defineConfig({5 // Other config settings67 plugins: [8 // Other plugins9 codeInput(),10 ],11});
Integrating Code Input into Block Content
In your schema file, add the code
type to your block content array of types:
block.ts
1defineField({2 name: 'copy',3 type: 'array',4 of: [5 defineArrayMember({6 type: 'block',7 }),8 defineField({9 name: 'code',10 type: 'code',11 options: {12 withFilename: true, // Optional13 },14 }),15 ],16}),
This snippet enables code input blocks throughout your content, complete with syntax highlighting.
Data model and type
1{2 _key: '123' // Shows up as added to block content3 _type: 'code',4 language: 'js',5 highlightedLines: [1, 2],6 code: 'const foo = "bar"\nconsole.log(foo.toUpperCase())\n// BAR',7 filename: 'filename.ts' // Shows up if enabled8}
1export type TCodeBlock = {2 language: string,3 highlightedLines: number[],4 code: string;5 filename: string;6};
Rendering Block Content with @portabletext/react
When you query your content from Sanity, you need a way to render the block content in your front-end application. The @portabletext/react
package is a powerful tool for this, allowing you to transform your queried block content into React components seamlessly.
Installing @portabletext/react
1yarn add @portabletext/react @portabletext/types
Setting Up the PortableText Custom Component
Once installed, you can import and use the PortableText
component to render your content. Here’s a simple setup:
custom-portable-text.tsx
1import { PortableText, PortableTextComponents } from '@portabletext/react';2import { PortableTextBlock } from '@portabletext/types';34import { TCodeBlock } from '@/types';56const components: PortableTextComponents = {7 block: {8 h1: ({ children }) => {9 return (10 <h1 className="scroll-m-32 text-2xl">11 {children}12 </h1>13 );14 },15 },16 types: {17 myCodeField: ({ value }: { value: TCodeBlock }) => {18 return <CodeBlock code={value} />;19 },20 },21};2223export default function CustomPortableText({24 value,25}: {26 value: PortableTextBlock[];27}) {28 return <PortableText components={components} value={value} />;29}
In the above example, components
is an object that tells @portabletext/react
how to render different types of content. For code blocks, we're pointing it to use our custom CodeBlock
component that we will set up now to render with prism-react-renderer
.
Styling with Prism React Renderer
To further enhance the appearance of your code blocks, install prism-react-renderer
:
1yarn add prism-react-renderer
Basic Setup
The setup below custom component or highlighter component which is used to add support for code block highlights and also includes language support.
code-block.tsx
1import { Highlight } from 'prism-react-renderer';23import { TCodeBlock } from '@/types';45type Props = {6 code: TCodeBlock;7};89export default function CodeBlock({ code: { code, filename, language } }: Props) {10 return (11 <Highlight code={code} language={language}>12 {({ style, tokens, getLineProps, getTokenProps }) => (13 <pre style={style}>14 <p className="opacity-70">{filename}</p>15 {tokens.map((line, i) => (16 <div key={i} {...getLineProps({ line })}>17 <span>{i + 1}</span>18 {line.map((token, key) => (19 <span key={key} {...getTokenProps({ token })} />20 ))}21 </div>22 ))}23 </pre>24 )}25 </Highlight>26 );27}28
The setup above will get your code block looking like the following:

Customise it Further
I went ahead and imported the themes
from prism-react-renderer
to style the code block like one of the theme extensions you can find in VS Code.
I also gave the span which displays the line numbers the Tailwind classes inline-block w-8 select-none
. I added the display and width property to make the code line up on each line as once you go from a single digit to double digits it slightly moves the code to the right.
I added the user select property so if someone wishes to copy the code, they can do so without copying the line numbers too.
code-block.tsx
1import { Highlight, theme } from 'prism-react-renderer';23export default function CodeBlock({ code: { code, filename, language } }: Props) {4 return (5 <Highlight theme={theme.shadesOfPurple} code={code} language={language}>6 {({ style, tokens, getLineProps, getTokenProps }) => (7 <pre style={style}>8 <p className="opacity-70">{filename}</p>9 {tokens.map((line, i) => (10 <div key={i} {...getLineProps({ line })}>11 <span className="inline-block w-8 select-none">{i + 1}</span>12 {line.map((token, key) => (13 <span key={key} {...getTokenProps({ token })} />14 ))}15 </div>16 ))}17 </pre>18 )}19 </Highlight>20 );21}22
Just as I posted this I remembered about showing off the lines you highlight. To highlight lines in Sanity open up the code block and click on the line you wish to highlight, the line should get a yellow background if its highlighted.
Now below for how to setup it so it renders highlighted lines on the frontend too.
code-block.tsx
1import { Highlight, theme } from 'prism-react-renderer';23export default function CodeBlock({ code: { code, filename, language, highlightedLines } }: Props) {4 return (5 <Highlight theme={theme.shadesOfPurple} code={code} language={language}>6 {({ style, tokens, getLineProps, getTokenProps }) => (7 <pre style={style}>8 <p className="opacity-70">{filename}</p>9 {tokens.map((line, i) => (10 <div key={i} {...getLineProps({ line })} className={highlightedLines.includes(i + 1) ? 'bg-background/50' : undefined}>11 <span className="inline-block w-8 select-none">{i + 1}</span>12 {line.map((token, key) => (13 <span key={key} {...getTokenProps({ token })} />14 ))}15 </div>16 ))}17 </pre>18 )}19 </Highlight>20 );21}22
Conclusion
Upgrading your code blocks with these tools not only improves readability but also the overall aesthetic of your content. It's an investment in your audience's experience on your site. Dive into these updates and see how your code snippets can shine!
Looking to enhance your digital content with beautifully styled code blocks? If integrating these features sounds daunting, worry not—I’m here to help. Get in touch if you need assistance implementing these updates, or if you're interested in more advanced customizations. Let’s make your code stand out!