4 min read

Supporting Visual Editing in your CMS

Learn how to implement support for Visual Editing in your CMS.
Table of Contents

Visual Editing is available in Beta on Pro and Enterprise plans

Visual Editing provides a way for Pro and Enterprise teams to edit content in real-time on their site when using a supported CMS workflow.

This doc provides steps for CMS providers who are interested in supporting Visual Editing in their CMS.

There are three steps to implement support for Visual Editing:

  1. Add a configuration option that indicates whether to include source maps in API responses
  2. Add encoded content source maps to API responses when enabled in the configuration
  3. Contact us when you’re ready to test your implementation:

Content source maps are identifiers that track where a piece of content comes from. They generally indicate what CMS the data is from (the origin) and what to do when it’s opened (through href or event handlers).

Vercel detects editable info on the page based on these source maps. When encoded, the source maps are represented as invisible unicode characters that can be added to any string.

To learn more about content source maps, read the specification.

This configuration option allows you to explicitly indicate whether to encode the content source maps. The encoded values are invisible, but they still add page weight. If you are using a feature like Next.js Draft Mode (formerly Preview Mode), you may want to set this value based on that.

We highly encourage implementing the configuration option as an optional boolean attribute. The default value should be determined based on the Vercel environment.

This option can be added anywhere that users would typically be able to define other configuration options in their code.

For instance, if users already define the config of their API client like this:

interface ClientConfig {
  id: string;
}
 
function setConfig({ id }: ClientConfig) {
  /* ... */
}

You could update it like this:

interface ClientConfig {
  id: string;
  encodeSourceMaps?: boolean;
}
 
function setConfig({
  id,
  encodeSourceMaps = process.env.VERCEL_ENV === 'preview',
}: ClientConfig) {
  /* ... */
}

Once you have enabled the option to include source maps in API responses, use the following steps to add the source map:

  1. Identify which parts of the API response will be rendered into the page. The encoded data can only be added to strings. For instance, an author’s name or the alt text for an image.

    Do not add source maps to fields that won’t be rendered into the page in a user-facing way. For instance, do not add to the id of a model or the src of an image.

  2. For these parts of the response, add to the existing string responses. The value that’s being appended should be created using @vercel/stega and the source map schema outlined below.

Editable fields must always include a JSON object that indicates what to do when they are opened. This JSON object supports three properties:

PropertyRequiredTypeDescription
originNo

string

The hostname of the data source (e.g. "sanity.io" or "contentful.com"). This field is used to determine what name to show in the UI for the "Open in ..." CTA and to filter edit events to a specific source.
hrefNo

string

The url to load when this field is opened (e.g. "domain.com/foo")
dataNo

any

Extra data to be included when emitting edit events (any JSON value)

All of these properties are optional, but it typically makes the most sense to use two of them at once.

To open an editable field as a link, use the origin and href properties.

To emit an open event for a field, use origin and data, where the data is any JSON value you need to be able to identify the field. You can then create an event listener in the client to listen for an edit:open event and react accordingly.

my-webpage.ts
window.addEventListener('edit:open', (event: CustomEvent) => {
  const { origin, data } = event.detail;
  if (origin !== 'your.origin') return;
  // Do something with data here...
});

If TypeScript gives you an error for using a CustomEvent, you can alleviate the problem by wrapping and casting the callback, like so: (<callback>) as EventListener.

There are two ways to indicate that field is editable. Both methods can co-exist in the same website or even the same page.

If an element has a [data-vercel-edit-info] attribute on it, it will be considered editable. In this scenario, the attribute should be set to the stringified JSON of the schema for the field.

If an element’s textContent contains an encoded string, it will be considered editable. In this scenario, the encoded string should be generated using vercelStegaEncode(json) from the @vercel/stega npm package.

If an image's alt attribute contains an encoded string, it will be considered editable.

@vercel/stega is a public npm package that exports some basic utilities for encoding and decoding JSON as hidden strings. To install the package, do the following:

Terminal
npm i '@vercel/stega'

Then you could write a function to encode edit info like the following:

my-webpage.ts
import { vercelStegaCombine } from '@vercel/stega';
 
function encodeEditInfo(text: string, href: string): string {
  return vercelStegaCombine(text, {
    origin: 'your.origin',
    href,
  });
}
Last updated on April 30, 2024