Troubleshooting Visual Editing
Troubleshooting overlays
Styling of editable fields is incorrect
If the text on the page is breaking out of its container (or its container is much wider than normal), it can be resolved by splitting the encoded text out from the original text.
Note
This is not due to the encoded characters themselves. This problem should only present itself if the element also uses negative letter-spacing in its CSS or is inside a <Balancer> component from react-wrap-balancer.
Then identify where the problematic element is rendered in code, for example:
export function MyComponent({ text }: { text: string }) {
return <h1>{text}</h1>;
}Rewrite using @vercel/stega to avoid any styling issues:
import { vercelStegaSplit } from "@vercel/stega";
export function MyComponent({ text }: { text: string }) {
const { cleaned, encoded } = vercelStegaSplit(text);
return (
<h1>
{cleaned}
<span style={{ display: "none" }}>{encoded}</span>
</h1>);
}If you find yourself doing this more than once, you might like to extract this logic to a reusable component:
import { vercelStegaSplit } from "@vercel/stega";
export default function Clean({ value }: { value: string }) {
const { cleaned, encoded } = vercelStegaSplit(value);
return encoded ? (
<>
{cleaned}
<span style={{ display: "none" }}>{encoded}</span>
</>) : (
cleaned
);
}
export function MyComponent({ text }: { text: string }) {
return (
<h1>
<Clean value={text} />
</h1>);
}Overlay displays over the wrong element
If the wrong element is highlighted when hovering, an additional attribute can be added to a containing element.
For example, if the following component highlights the <h1> and you want it to highlight the <section> element:
<section>
<h1>{dynamicTitle}</h1>
<div>Hardcoded Tagline</div>
</section>Add a data attribute to highlight the correct item:
- For Visual Editing with
@sanity/visual-editing, adddata-sanity-edit-target - For Vercel Visual Editing (Vercel's Edit Mode), add
data-vercel-edit-target
<section data-sanity-edit-target>
<h1>{dynamicTitle}</h1>
<div>Hardcoded Tagline</div>
</section>Troubleshooting stega-encoding
As of @sanity/visual-editing 5.5.0 and Sanity Studio 6.6.0, two common sources of stega contamination are handled automatically. First, clipboard copies are cleaned: when Visual Editing is active, <VisualEditing /> strips stega from clipboard data when users copy text from the preview page, so pasting into external tools like Notion, Slack, or spreadsheets no longer produces invisible characters. You can opt out of this behavior with the keepStegaOnCopy prop if needed.
Second, Studio field pastes are cleaned automatically: pasting stega-contaminated text into any Sanity Studio primitive field (string, text, URL, slug, number, tags, and arrays of primitives) now strips stega before storing the value. Portable Text already handled this; as of 6.6.0, all primitive fields do as well.
There are weird characters in your DOM
These are most likely stega-encoded strings. They are a subset of HTML entities that, when rendered, produce invisible output. Below is the string value of “Oxford Shoes” when it contains a stega-encoded Content Source Map:
Oxford Shoes​​​​‌‍​‍​‍‌‍‌​‍‌‍‍‌‌‍‌‌‍‍‌‌‍‍​‍​‍​‍‍​‍​‍‌​‌‍​‌‌‍‍‌‍‍‌‌‌​‌‍‌​‍‍‌‍‍‌‌‍​‍​‍​‍​​‍​‍‌‍‍​‌​‍‌‍‌‌‌‍‌‍​‍​‍​‍‍​‍​‍‌‍‍​‌‌​‌‌​‌​​‌​​‍‍​‍​‍‌‌‍‌‍‍‌‌​‌‌‌‌‍​‌‌‍​​‍‌‌‍‌‌‌‍‌​‌‍‍‌‌‌​‌‍‍‌‌‍‍‌‍‌​‍‌‌​‌‌​‌‌‌‌‍‌​‌‍‍‌‌‍​‍‍‌​‌‍​‌‌‍‍‌‍‍‌‌‌​‌‍‌​‍‍‌‍​‍‌‌‌‌‍‍‌‌‍​‌‍‌​​‍‌​‍‌‍‌‌‌‍‌‌‍‍‌‌‍​​‍‌‍‍‌‌‍‍‌‌​‌‍‌‌‌‍‍‌‌​​‍‌‍‌‌‌‍‌​‌‍‍‌‌‌​​‍‌‍‌‌‍‌‍‌​‌‍‌‌​‌‌​​‌​‍‌‍‌‌‌​‌‍‌‌‌‍‍‌‌​‌‍​‌‌‌​‌‍‍‌‌‍‌‍‍​‍‌‍‍‌‌‍‌​​‌‌‍​‍​‍‌​‌‌​‌‍‌‍​‌‍‌‍​‌‌‍​‍​‍‌‌‍​‌​‌‌‍​‍​‌​‍‌​‌​‌‍‌‌​‌‌​‌‍​‍‌‌‍​‌​​‌​‌‍‌‍‌‍​‍‌‌‍​‍‌‍​‌‌‍‌​​‍​‌‍‌‌‌‍‌‌​​​‍‌​​‍‌‍‌‌​​​‌​​‍‌‌​‌‍‌‌​​‌‍‌‌​‌‌​‌‍‍​‌‍‌‍‌‌​‍‌​​‌‍​‌‌‌​‌‍‍​​‌‌‌​‌‍‍‌‌‌​‌‍​‌‍‌‌​‍‌‌​‌‍‌‍‌‍​​‌‌​​‌​‍‌‍‌‌‌​‌‍‌‌‌‍‍‌‌​‌‍​‌‌‌​‌‍‍‌‌‍‌‍‍​‌‍​‍‌‍​‌‌​‌‍‌‌‌‌‌‌‌​‍‌‍​​‌‌‍‍​‌‌​‌‌​‌​​‌​​‍‌‌​​‌​​‌​‍‌‌​​‍‌​‌‍​‍‌‌​​‍‌​‌‍‌‌‍‌‍‍‌‌​‌‌‌‌‍​‌‌‍​​‍‌‌‍‌‌‌‍‌​‌‍‍‌‌‌​‌‍‍‌‌‍‍‌‍‌​‍‌‌​‌‌​‌‌‌‌‍‌​‌‍‍‌‌‍​‍‍‌​‌‍​‌‌‍‍‌‍‍‌‌‌​‌‍‌​‍‍‌‍​‍‌‌‌‌‍‍‌‌‍​‌‍‌​​‍‌‍‌‍‍‌‌‍‌​​‌‌‍​‍​‍‌​‌‌​‌‍‌‍​‌‍‌‍​‌‌‍​‍​‍‌‌‍​‌​‌‌‍​‍​‌​‍‌​‌​‌‍‌‌​‌‌​‌‍​‍‌‌‍​‌​​‌​‌‍‌‍‌‍​‍‌‌‍​‍‌‍​‌‌‍‌​​‍​‌‍‌‌‌‍‌‌​​​‍‌​​‍‌‍‌‌​​​‌​​‍‌‍‌‌​‌‍‌‌​​‌‍‌‌​‌‌​‌‍‍​‌‍‌‍‌‌​‍‌‍‌​​‌‍​‌‌‌​‌‍‍​​‌‌‌​‌‍‍‌‌‌​‌‍​‌‍‌‌​‍‌‍‌‌‌‍‌​‍‌‍‍‌​‌​​‌‍​‌‌‍​‌‍‌‌​‌‌​‍‌‍‌‌‌‍‌‌‍‍‌‌‍​​‍‌‍‌‌​‌‍‌‍‌‍​​‌‌​​‌​‍‌‍‌‌‌​‌‍‌‌‌‍‍‌‌​‌‍​‌‌‌​‌‍‍‌‌‍‌‍‍​‍‌‍‌‍‍‌‌​‌​‌​‌​‍‌‍​‌‌‍‌‍‌‌​​‌​‍​‍‌‌
When rendered in an HTML document, this string will still display as “Oxford Shoes.” You can use this tool to test the string by pasting the value above into the “Encoded” input field.
Comparing field values doesn’t work in preview mode
Your application likely evaluates values from the Content Lake to perform specific logic. If these values contain invisible encoded metadata, they may no longer work.
For example, imagine a function that determines that a Sanity document's market value is the same as the current market:
function showDocument(document: SanityDocument, currentMarket: string) {
return document.market === currentMarket
}Without stega enabled, this function works as expected. However, if document.market contains encoded metadata, this comparison will fail.
If document.market is never shown on the page and will not benefit from Visual Editing, filtering it out of the stega encoding process is recommended. You can pass a filtering function to stega.filter when configuring the client.
Alternatively, clean the value before comparing it:
import {stegaClean} from "@sanity/client/stega"
import type {SanityDocument} from "@sanity/client"
function showDocument(document: SanityDocument, currentMarket: string) {
return stegaClean(document.market) === currentMarket
}Since you'll likely do this more than once, consider extracting to a helper function.
Note: as of Sanity Studio 6.6.0, stega contamination in stored document data caused by copy-pasting preview content into Studio fields is handled automatically by the Studio paste handler. The advice to use stegaClean() in frontend application code for string comparisons and URL construction remains correct and unchanged.
Stega appears in element attributes, head, or scripts
Stega in rendered visible text is intentional. It powers click-to-edit. However, stega landing in HTML element attributes (such as class, id, href, src, style, or data-* attributes), inside <head> (page title, meta[content], JSON-LD), in <script> or <style> text content, in <textarea> form values, or baked into the page URL always causes bugs and must be avoided.
The onSuspiciousStega callback on <VisualEditing /> is an opt-in tool to detect these cases during development. It receives an array of reports, each with a report.kind property indicating where the stega was found.
<VisualEditing
onSuspiciousStega={(reports) => {
for (const report of reports) {
console.warn(`Stega found in ${report.kind}`, report)
}
}}
/>Performance cost
The onSuspiciousStega callback runs a full DOM audit using TreeWalker and MutationObserver and has a performance cost. It is most useful during development and debugging.
Possible report.kind values are: attribute, head, script, style, form-value, and url.
Troubleshooting embedded studios
When using Visual Editing with embedded studios (studios that render on a route in your frontend app), do not include Visual Editing or SanityLive components in the root or layout component for your studio.
We recommend creating dedicated content and studio layouts so you can keep your studio separate from the frontend visual editing components.