Kim Björkman
5 min readSep 16, 2019

Today I thought I’d show you how to extend the rich-text editor in Sanity to add allow you to add inline images/icons. I’m using Gatsby here but anything goes. As always, I wont take up much of your time so let’s get to it.

Sanity uses what’s called Portable Text. Take a moment to read over this excerpt from the Sanity docs;

Portable Text is built on the idea of rich text as an array of blocks, themselves arrays of children spans. Each block can have a style and a set of mark definitions, which describe data structures distributed on the children spans. Portable Text also allows for inserting arbitrary data objects in the array, only requiring _type-key. Portable Text also allows for custom content objects in the root array, enabling editing- and rendering environments to mix rich text with custom content types.

This means that the text that you write in the editor becomes accessible to you via the API as JSON. It may seem a bit intimidating at first but the control you get over the input/output in the end is well worth it.

Going further i’ll assume you have a project with a studio set up. There are plenty of good starters to go with: https://www.sanity.io/create.

Once you have your project set up head into the schemas folder of your studio and create a file blockContent.js if you don’t already have one from the starters. We also have to include it in our main schemas.js of course. It could look something like this:

This file describes your rich-text editors options. We can customize this freely because of the awesome work from the people over at Sanity. The important part here to take note of is marks: which is where we will be describing our inline image functionality to the studio.

Structures you declare under marks will become available in the studio editor in the top as buttons you can click on.

Under marks you can see two more structures named annotations and decorators. Again the Sanity docs come to the rescue;

Marks is how we mark up inline text with additional data. Marks comes in two forms: Decorators and Annotations. Decorators are marks as simple string values, while Annotations are keys to a data structure.

This means creating an additional object under Decorators will create a button for you to click in the toolbar that will surround the piece of text you have selected at the time of clicking with a <strong> tag or whatever else you might want to do with it. This comes in very handy lots of times but doesnt quite cut it for our current task at hand. What we want, is Annotations.

Annotations are keys to a data structure and makes it possible to embed rich content structures on top of inline text. We can for example insert, you guessed it, images inline into our rich text. Let’s update our blockContent.js file;

Now we have added the description for our image which we will place inline in our text. We give it a title, a name, an icon and a type of image which Sanity will use to allow us to upload an image. Add blockContent to one of your schemas. In this case we add it to an object called contentblock which will represent a block of content to the user;

Then start up the studio with npm start and you should be able to see something like this on your content block, which is the icon we specified earlier, and what it looks like once you press it;

This is it for the first part, we have described to the studio what we want, now all we got to do is extract this data and process it into the output that we want.

Head over to your web projects root folder, and create a new component BlockContent if you don’t already have one. This will be the component that takes the JSON result from our API request and transform it into whatever we want. It could look something like this;

You will see that we import two things here apart from React. We import @sanity/block-content-to-react and a component inline-icon which just returns an image that has some css for height and its display value set to inline-block.

First let’s run npm install --save @sanity/block-content-to-react which is a package supplied by the people over at Sanity to render our data. The way it will render it will depend on the serializers that are supplied, which is what we have set up above.

So whenever the serializer runs upon mark data that has a _type of inlineicon it will pass the information for the data that the mark refers to and render our image inside the block of text. I’ve set it up here so the alt value will be equal to the text that was selected when you added the Annotation. Don’t forget about the people using assistive tech!

You will of course need to examine your data so that you make sure to pass in the right information to your BlockContent component.

Now you can freely import and use <BlockContent blocks={ this.props.body || [] }/> in your views and your images should show up beautifully.

I hope this gave you a hint of how to use annotations and how to customize the rendering of portable text in Sanity. If you want more in depth information or have any questions head over to the sanity docs for the editor or leave a comment below.

Happy Coding!

Kim Björkman

Developer based in Sweden/Japan. I write about problems and interesting things I run into. Currently happily coding at `Sunny at Sea` in Stockholm, Sweden.