Portable Text Editor: Superscript/Subscript decorators not displaying correctly

4 replies
Last updated: Jan 31, 2023
Hey, I am following https://www.sanity.io/docs/customizing-the-portable-text-editor#e6401a8fe843 to try and add super and sub script options to the editor, but nothing is displaying correctly.
import {GrSubscript, GrSuperscript} from 'react-icons/gr'
const SuperscriptDecorator = props => (
  <span style={{backgroundColor: 'yellow'}}>{props.children}</span>
)
const SubscriptDecorator = props => (
  <span style={{backgroundColor: 'yellow'}}>{props.children}</span>
)
...
...
marks: {
          decorators: [
            {title: 'Strong', value: 'strong'},
            {title: 'Emphasis', value: 'em'},
            {title: 'Underline', value: 'underline'},
            {title: 'Superscript', value: 'sup', icon: GrSuperscript, component: SuperscriptDecorator},
            {title: 'Subscript', value: 'sub', icon: GrSubscript}
          ],
}
When I have just the icons, sanity runs but the icons aren't being imported (see screenshot). When I also add in the component to display the superscript, I get an error in the studio (screenshot). Anyone have any ideas what I'm doing wrong? This is sanity v2.35.0
AI Update

I can see the issue! You're using Sanity v2.35.0, and there are two problems with your code:

The Icon Issue

React Icons components need to be wrapped in a function that returns the component. Try this:

marks: {
  decorators: [
    {title: 'Strong', value: 'strong'},
    {title: 'Emphasis', value: 'em'},
    {title: 'Underline', value: 'underline'},
    {
      title: 'Superscript', 
      value: 'sup', 
      icon: () => <GrSuperscript />,  // Wrap in a function
      component: SuperscriptDecorator
    },
    {
      title: 'Subscript', 
      value: 'sub', 
      icon: () => <GrSubscript />,  // Wrap in a function
      component: SubscriptDecorator
    }
  ],
}

The Component Issue

Your decorator components also need to render the actual HTML elements (<sup> and <sub>), not just styling wrappers:

const SuperscriptDecorator = props => (
  <sup>{props.children}</sup>
)

const SubscriptDecorator = props => (
  <sub>{props.children}</sub>
)

The yellow background styling you had was just for testing, but it won't create the actual superscript/subscript effect. The <sup> and <sub> HTML elements are what actually position the text correctly in the editor.

Complete Working Example for v2

import {GrSubscript, GrSuperscript} from 'react-icons/gr'

const SuperscriptDecorator = props => (
  <sup>{props.children}</sup>
)

const SubscriptDecorator = props => (
  <sub>{props.children}</sub>
)

// In your schema:
marks: {
  decorators: [
    {title: 'Strong', value: 'strong'},
    {title: 'Emphasis', value: 'em'},
    {title: 'Underline', value: 'underline'},
    {
      title: 'Superscript', 
      value: 'sup', 
      icon: () => <GrSuperscript />,
      component: SuperscriptDecorator
    },
    {
      title: 'Subscript', 
      value: 'sub', 
      icon: () => <GrSubscript />,
      component: SubscriptDecorator
    }
  ],
}

Note: If you were on Sanity v3, the syntax would use blockEditor.icon and blockEditor.render instead, as shown in this community answer, but that's not what you need for v2.

Show original thread
4 replies
I worked around the same problem with
icon: () => 'Super'
Just tested with latest sanity versions and I got it working fine with these:

const SuperIcon = () => <div>x<sup>2</sup></div>
const SuperDecorator = props => <sup>{props.children}</sup>
const SubIcon = () => <div>x<sub>2</sub></div>
const SubDecorator = props => <sub>{props.children}</sub>
...

decorators: [
...
   { title: "Sub", value: 'sub', icon: SubIcon, component: SubDecorator },
   { title: "Super", value: 'super', icon: SuperIcon, component: SuperDecorator },
]
Oh your using old sanity. See this document for old object format for decorator:

https://www.sanity.io/help/schema-deprecated-blockeditor-key

decorators: [
  {
    title: 'Highlight',
    value: 'highlight',
    blockEditor: {
      icon: MarkerIcon,
      render: highlightRender,
    },
  },
],
Thats it, adding blockEditor worked! Thank you

Sanity – Build the way you think, not the way your CMS thinks

Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.

Was this answer helpful?