return to homepage@tanselberkant

Rendering Code Blocks in a Next.js and Sanity Project

How to render and copy code blocks using libraries such as @sanity/code-input and react-refractor

Introduction

In this blog post, I will share my journey of implementing code block rendering in a Next.js and Sanity project. Initially, I used to include images instead of actual code blocks in my blog posts. However, in order to make my articles more accessible and developer-friendly, I decided to tackle this challenge. After overcoming various hurdles, I successfully achieved the desired outcome. Now, I want to share the process of how I accomplished it.

Prerequisites

Before diving into the implementation details, make sure you have the following dependencies installed:

@sanity/code-input package (version 4.1.1 or higher)
react-refractor package
@portabletext/react package
uuid package

Step 1: Installing and Configuring @sanity/code-input

To begin, install the @sanity/code-input package by running the following command:

yarn add @sanity/code-input@^4.1.1

Next, open the sanity.config.ts file and add the codeInput plugin to the plugins array:

import { codeInput } from '@sanity/code-input'

export default defineConfig({
	// ...
	plugins: [codeInput()]
})

Step 2: Modifying the Schema to Support Code Blocks

In your post.ts schema file, locate the existing defineField block responsible for rendering the body content. Add the following code block definition within the defineArrayMember section:

defineArrayMember({
  type: 'code',
  name: 'myCodeField',
  title: 'Code with all options',
  options: {
    language: 'javascript',
    languageAlternatives: [
      { title: 'Javascript', value: 'javascript' },
      { title: 'TypeScript', value: 'typescript' },
      { title: 'tsx', value: 'tsx' },
    ],
    withFilename: true,
  },
}),

Step 3: Implementing Code Block Rendering in the Frontend

To render the post body, we will be using the PortableText component from the @portabletext/react package. Modify your code as follows:

import { PortableText } from '@portabletext/react'
;<PortableText onMissingComponent={false} value={post.body} components={RichTextComponents} />

Step 4: Customizing the Rendering of Code Blocks

In order to customize the rendering of code blocks, we need to define a custom component within the RichTextComponents object. Install the react-refractor package by running:

yarn add react-refractor

Update your code as shown below:

import Refractor from 'react-refractor'
import { v4 as uuid } from 'uuid'

export const RichTextComponents = {
	types: {
		// ...
		myCodeField: ({ value }) => {
			const iconId = uuid()
			return (
				<div className="text-dark-textDescription my-8 bg-gray-700 px-4 py-3">
					<Refractor language="js" value={value.code} />
					<div className="flex justify-end">
						<ClipboardIcon
							id={`clipboard-icon-${iconId}`}
							className="h-6 w-6 cursor-pointer delay-75 hover:text-gray-500"
						/>
					</div>
					<script
						dangerouslySetInnerHTML={{
							__html: `
                document.getElementById('clipboard-icon-${iconId}').addEventListener('click', function() {
                  const textToCopy = ${JSON.stringify(value.code)};
                  const textarea = document.createElement('textarea');
                  textarea.value = textToCopy;
                  document.body.appendChild(textarea);
                  textarea.select();
                  document.execCommand('copy');
                  document.body.removeChild(textarea);
                });
              `
						}}
					/>
				</div>
			)
		}
	}
}

Update your code as shown below:

Conclusion

By following the steps outlined in this blog post, I successfully integrated code block rendering into my Next.js and Sanity project. I overcame the initial challenge of including images in place of code blocks, and now my blog posts are more accessible and developer-friendly. I hope this step-by-step guide helps you in implementing code block rendering in your own projects.