Step Level Up
customizing-sanity-rich-text-editor-comprehensive-guide
M
Mahadev Mandal

· min read

Customizing the Sanity Rich Text Editor: A Comprehensive Guide

Sanity is a powerful and flexible headless CMS that allows developers to create custom content management solutions. One of the key features of Sanity is its rich text editor, which can be customized to meet specific needs. In this blog post, we'll walk through the steps to customize the Sanity rich text editor by adding new formatting options and annotations.

Setting Up Your Project

Before we dive into the customization, let's ensure that your project is set up correctly. Here is a basic structure of your Sanity project files involved in the customization:

File Structure

my-sanity-project/
├── schemaTypes/
│   ├── RichTextEditor.jsx
│   ├── posts.js
│   ├── index.js
├── sanity.config.js

1. Defining Custom Rich Text Editor (RichTextEditor.jsx)

First, we'll define a custom rich text editor schema. This schema includes additional formatting options like superscript, subscript, and an external link annotation. Here's the complete code:

import React from 'react';

const externalLinkLogo = (
  <svg
    stroke="currentColor"
    fill="none"
    strokeWidth={2}
    viewBox="0 0 24 24"
    strokeLinecap="round"
    strokeLinejoin="round"
    height="1em"
    width="1em"
    xmlns="http://www.w3.org/2000/svg"
  >
    <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" />
    <polyline points="15 3 21 3 21 9" />
    <line x1={10} y1={14} x2={21} y2={3} />
  </svg>
);

const SuperscriptIcon = () => (
  <span>
    Sup<sup>2</sup>
  </span>
);
const SuperscriptDecorator = (props) => <sup>{props.children}</sup>;

const SubscriptIcon = () => (
  <span>
    Sub<sub>2</sub>
  </span>
);
const SubscriptDecorator = (props) => <sub>{props.children}</sub>;

export default {
  title: 'Content',
  name: 'RichTextEditor',
  type: 'array',
  of: [
    {
      type: 'block',
      marks: {
        decorators: [
          { title: 'Bold', value: 'strong' },
          { title: 'Italic', value: 'em' },
          { title: 'Underline', value: 'underline' },
          {
            title: 'Superscript',
            value: 'superscript',
            icon: SuperscriptIcon,
            component: SuperscriptDecorator,
          },
          {
            title: 'Subscript',
            value: 'subscript',
            icon: SubscriptIcon,
            component: SubscriptDecorator,
          },
        ],
        annotations: [
          {
            name: 'link',
            type: 'object',
            title: 'External Link',
            icon: externalLinkLogo,
            fields: [
              {
                name: 'external',
                type: 'url',
                title: 'URL',
                validation: (Rule) =>
                  Rule.uri({
                    allowRelative: false,
                    scheme: ['http', 'https', 'mailto', 'tel'],
                  }),
              },
              {
                title: 'Open in new tab',
                name: 'blank',
                type: 'boolean',
              },
            ],
          },
        ],
      },
    },
  ],
};

2. Creating the Post Schema (posts.js)

Next, we create a post schema that includes the custom rich text editor as the body field. Here's how you define it:

import { defineField, defineType } from 'sanity';

export default defineType({
  name: 'post',
  title: 'Post',
  type: 'document',
  fields: [
    defineField({
      name: 'title',
      title: 'Title',
      type: 'string',
    }),
    defineField({
      name: 'slug',
      title: 'Slug',
      type: 'slug',
      options: {
        source: 'title',
        maxLength: 96,
      },
    }),
    defineField({
      name: 'mainImage',
      title: 'Main image',
      type: 'image',
      options: {
        hotspot: true,
      },
    }),
    defineField({
      name: 'publishedAt',
      title: 'Published at',
      type: 'datetime',
    }),
    defineField({
      name: 'body',
      title: 'Body',
      type: 'RichTextEditor',
    }),
  ],
});

3. Aggregating Schemas (index.js)

To ensure all schemas are recognized, you need to aggregate them in an index.js file:

import post from './posts';
import RichTextEditor from './RichTextEditor';

export const schemaTypes = [post, RichTextEditor];

4. Configuring Sanity (sanity.config.js)

Finally, configure Sanity to use your custom schemas:

import { defineConfig } from 'sanity';
import { deskTool } from 'sanity/desk';
import { visionTool } from '@sanity/vision';
import { schemaTypes } from './schemaTypes';

export default defineConfig({
  name: 'default',
  title: 'my-sanity-project',

  projectId: 'XXXXXXXX',
  dataset: 'production',

  plugins: [deskTool(), visionTool()],

  schema: {
    types: schemaTypes,
  },
});

Customizing the Editor

Adding New Decorators

In the RichTextEditor.jsx, we've added superscript and subscript decorators. Decorators are used to apply inline styles to text, such as bold or italic. We've defined two new decorators:

  • Superscript: Displays text as superscript.
  • Subscript: Displays text as subscript.

Adding New Annotations

Annotations in Sanity are used for more complex text modifications, like adding links. In this case, we've added an external link annotation with a custom SVG icon. This allows users to insert external links into their content.

Icons and Components

We've also added custom icons and components for our decorators and annotations. These are defined using React components and passed into the respective schema fields.

Conclusion

Customizing the Sanity rich text editor allows you to tailor the content creation experience to your specific needs. By following the steps outlined in this guide, you can add new formatting options and annotations, making your editor more powerful and user-friendly.

Feel free to expand on this foundation by adding more customizations, such as additional decorators, custom block types, or more complex annotations. With Sanity's flexibility, the possibilities are endless!

Comments

Loading...

Mahadev Mandal

Written by Mahadev Mandal

I am a web developer with expertise in HTML, CSS, Tailwind, React.js, Next.js, Gatsby, API integration, WordPress, Netlify functions, the MERN stack, fullstack development, and NestJS.