Skip to content
Sanity
Get started
  • Sanity Studio - Flexible editing environment
  • Content Lake - Real-time database
  • Developer experience - Tooling you love
  • Structured content - The philosophy behind Sanity
  • Review changes - View edits & rollback instantly
  • Image pipeline - On-demand transformations
  • E-commerce - Better shopping experiences
  • Marketing sites - Control your story
  • Products & services - Innovate and automate
  • Mobile apps - Content backend for every OS
  • Aether - Unique digital shopping experience
  • Morning Brew - Omnichannel media distribution
  • InVision - Delivering exceptional customer experiences
  • DataStax - Personalization for global audience
  • React
  • Gatsby
  • Next
  • Nuxt
  • Eleventy
  • Netlify
  • Vercel
  • Algolia
  • Documentation
  • Reference
  • Guides
  • Resource library
  • Headless CMS
  • Tools & plugins
  • Project showcase
  • Schemas & snippets
  • Agency partners
  • Technology partners
  • Get support
  • Share your work
  • 5 Disadvantages Of Wordpress That Are Holding You Back
EnterprisePricing
Contact salesLog inGet started
Published December 20th 2018

Introducing the new Editor for Portable Text

With the new editor for Portable Text, developers get a pocket full of new features for configuring and customizing a productive editing environment for deeply typed content.

Even Eidsten Westvang

Even is a Sanity.io co-founder and product person

Central to Sanity is the ability to work with content with all the advantages of treating it as data. Non-obviously perhaps, that makes us pretty obsessed with text. We are typing words into Sanity everyday when we're writing blog posts, documentation, and developing new features.

Treating text as data is super hard. For authors, it needs to look like a modern text editor. This while developers design flexible schemas that combine text with embedded objects and where the end result is data that you can subject to queries and joins.

In our latest release, we ship a new editor for Portable Text. On the surface it may not seem that much has happened, but much work has happened on its underpinnings and machinery. We're super proud of our team that has spent hours developing, testing, finding edge cases (oh, the edge cases!), and obsessing over details.

Run this line in your command line to upgrade and get the new editor in your Sanity project:

npm i -g @sanity/cli && sanity upgrade

What we now have is an editor that works as expected out of the box, but gives you extensive possibilities for configuration and customization. Most of it is done in the simple JavaScript configuration you might already know, while previews, toolbar icons, and block actions can be customized with React components. So let's dive into some of the new things!

Have it your own style

The editor for Portable Text comes with a set of styles that translate well to those you'll find in HTML. You might not be targeting HTML though. While it has always been possible to add and configure block styles, you can now also configure how these styles render in the editor using markup and CSS modules. This means you can tune your editor to be aligned with your organization’s design system.

A custom title set in Garamond

Total render control!

One of the big advantages of Portable Text is the ability to add marks, that is, to annotate inline text with simple keys or complex typed content structures. We have now made it easy to add your own icons via the schema configuration. You can pass in simple strings, or React components (yeah, you can theoretically render a video in your toolbar – but you probably shouldn't). You can also control how marks in the inline text are rendered, for example, if you want to add highlight functionality.

import { HighlightIcon, Highlight } from './decorators/Highlight'

marks: {
  decorators: [
    {title: 'Strong', value: 'strong'},
    {title: 'Emphasis', value: 'em'},
    {title: 'Code', value: 'code'},
    {
      title: 'Highlight',
      value: 'highlight',
      blockEditor: {
        icon: HighlightIcon,
        render: Highlight
      }
    }
  ],
  ...
}

And in ./decorators/Highlight.js:

import React, {Fragment} from 'react'
import PropTypes from 'prop-types'
import styles from './Highlight.css'


const HighlightIcon => {
  return <Fragment>🖍</Fragment>
}

const Highlight = props => {
  return <span className={styles.root}>{props.children}</span>
}

Highlight.propTypes = {
  children: PropTypes.node.isRequired
}

export default {
  Highlight,
  HighlightIcon
}

Tailored paste handling

Now, this is pretty cool. We left you hooks to override and tune how content should be pasted into the editor. The editor already knows to deal with a lot of weird edge cases from Word documents. And it deals copy-pasted text from Google Docs too. But perhaps you have a legacy system with some special markup, or want to make it easy for editors to be able to copy paste content from the old website into the editor and have some parts be transformed into some custom content blocks.

An experiment we did with pasting markdown into the editor

We also updated the tool for working programmatically with Portable Text to make it easier to design customizations like this.

Validations and Actions

If you add validation rules to your markers, the warnings will now be highlighted in the margin, and your editors can activate the annotation modal directly from the validation menu. Perhaps you want to make sure that all images have got an alternative text, or warn editors if they use the http:// and not https:// URL in a link.

With Actions you can pass the content of a block to a React component that renders in the margin. This can be useful if you want to create workflows that triggers on certain strings or content types. You can, for example, make a thing that looks at your text for product names, and makes it easy to generate an internal reference when they appear.

Open Sourced Specification of Portable Text

It has always been a core idea of Sanity to have deeply typed content. Rich text is too often just left in the hands of markdown or HTML. While they're two perfectly good formats for what they're made for, they have no business as the storage format in a modern content backend.

We needed something that made it possible to have nested typed content structures, while being nimble for a WYSIWYG editor and that could be serialized into whatever markup or data structure you needed it for, without to much hassle. We wanted it to be JSON out of the box, and not leave the burden of transpiling XML on our users. That's how Portable Text was born. Since we find it mighty useful, we wanted to share it with the world. On www.portabletext.org you can find the specification and links to various tooling. We think it would have been super fun if someone decided to adapt it to their own use case.

Wrap it!

In order to add your own custom marker renderers, or actions, you have to pass those as props into the editor. It's fairly straight forward if you know some React:

import React from 'react'
import {BlockEditor} from 'part:@sanity/form-builder'
import renderCustomMarkers from '../renderCustomMarkers'

export default class ArticleBlockEditor extends React.PureComponent {
  render() {
    return (
      <div>
        <BlockEditor
          {...this.props}
          renderCustomMarkers={renderCustomMarkers}
        />
      </div>
    )
  }
}

A byproduct of this is of course that it's easy to wrap the editor in whatever you may desire. Be it real-time text statistics (you have access to the whole document in this.props) or perhaps be able to send the text to a text-to-speech API as we did with our SSML editor.

No more locking

With this upgrade, all fields in the Sanity Studio have support for real-time collaboration. You can sit on your desktop hammering away, while your co-worker fixes your spelling errors at the same time.

There's still a caveat – we still need to correctly handle the caret positions of users writing within the same paragraph. Annoyingly your caret position resets to the top of the block when other patches are applied to the same block. We'll be working more on collaboration in the new year and this is near the top of lists of things to improve.

The last large upgrade in an amazing year!

We hope you feel our enthusiasm for this rich text editor when you try it out. It seems like an appropriate occasion to note the passing of Evelyn Berezin, the creator of the first word processor, who sadly passed away at 93. We all owe Evelyn our gratitude for her efforts in paving the road and launching a revolution for all of us who friviously type on digital sheets.

This will be the last large feature upgrade in 2018. But since the calendar shows December 20th, we feel that it is perhaps reasonable. It has been an absolutely amazing year for us at Sanity HQ! We look forward to seeing you after the holidays and tell you some other exciting things we have been working on lately with some of our friends.

Page content

  • Have it your own style
  • Total render control!
  • Tailored paste handling
  • Validations and Actions
  • Open Sourced Specification of Portable Text
  • Wrap it!
  • No more locking
  • The last large upgrade in an amazing year!

Platform

Structured ContentDeveloper experienceContent LakeSanity StudioSecurity & Compliance
  • Sanity vs Contentful
  • Sanity vs Strapi
  • Sanity vs Wordpress
  • Sanity vs Adobe Experience Manager
  • Sanity vs Hygraph
  • Sanity vs Sitecore
  • Sanity vs Storyblok
  • Sanity vs Contentstack
  • Sanity vs Prismic
  • Sanity vs Drupal
  • Sanity vs ButterCMS

Resources

Documentation
  • React Blog
  • Gatsby Blog
  • Next.js Landing Pages
  • Progressive Web Application
  • Single Page Application
  • Svelte & Typescript App
  • Vue & Tailwind Blog
  • Developer Portfolio Templates
  • Form validation with Yup
  • Live Preview with Next.js and Sanity.io
Resource library
  • Agency partners
  • Technology partners
  • Blog Template
  • Personal Website Template
  • Developer Portfolio Templates
  • All Templates
Case Studies
  • Headless CMS
  • What is an API CMS
  • Static Sites 101
  • Headless SEO
  • Localization
  • GraphQL vs REST
  • What is a DXP?
  • Typescript 101
  • Content as a Service
  • Ecommerce SEO
  • React CMS
  • Next.JS CMS
  • CMS for Shopify
  • Content platform
  • Multilingual CMS
  • Static Site CMS
  • Gatsby CMS
  • Node CMS
  • E-commerce CMS
  • Vue CMS
  • Angular CMS
  • GraphQL CMS
  • Newspaper CMS
  • Magazine CMS
  • CMS for apps
  • Remix CMS

Company

Contact SalesEnterpriseCareersTerms of ServiceAccessibility Statement

Stay connected

  • GitHub
  • Slack
  • Twitter
  • YouTube
  • Stack Overflow
  • Blog RSS
  • Newsletter
©Sanity 2023