How it works
Enable the preview environment
Set
PUBLIC_SANITY_VISUAL_EDITING_ENABLED=true in the Astro app’s environment variables. This switches loadQuery() to use the drafts perspective and enables stega encoding.Open the Presentation tool in Studio
Navigate to the Presentation plugin in your Sanity workspace. It loads the preview URL (
SANITY_STUDIO_PREVIEW_ORIGIN) inside an iframe.Click any editable element
Stega-encoded strings in the rendered HTML carry invisible metadata that the
VisualEditing overlay reads to map DOM elements back to their Sanity document fields. Clicking an element opens the correct field in the Studio panel.Stega encoding
When Visual Editing is active,loadQuery() passes stega: true to the Sanity client. This embeds invisible Unicode characters (zero-width sequences) into string values returned by GROQ queries. The @sanity/visual-editing overlay reads these characters to determine which document and field path each piece of text belongs to, enabling click-to-edit without any custom data attributes.
Use stegaClean() from @sanity/client/stega when you need the raw string value — for example, when comparing a field value to a known constant or passing it to a non-rendering function:
SanityLiveUpdater component
astro-app/src/components/SanityLiveUpdater.astro is an Astro island that subscribes to the Sanity Live Content API and reloads the page when content changes are detected.
- In static mode (Visual Editing disabled): not rendered.
- In Visual Editing mode: rendered in every page’s
<Layout>. Connects to the Live Content API using a server-injected read token and callswindow.location.reload()after a 500 ms debounce when a matching sync tag event fires.
define:vars to keep it out of client JS bundles:
VisualEditingMPA React component
astro-app/src/components/VisualEditingMPA.tsx wraps @sanity/visual-editing/react’s <VisualEditing> component and adds an MPA-compatible HistoryAdapter.
The standard @sanity/astro VisualEditing component does not pass a history adapter, so Presentation Tool navigation events (when you click a document location in Studio) are silently dropped. VisualEditingMPA solves this by implementing HistoryAdapter.update() as a full-page window.location.href navigation:
Enabling Visual Editing
Visual Editing is controlled by thePUBLIC_SANITY_VISUAL_EDITING_ENABLED environment variable in the Astro app.
| Variable | Value | Effect |
|---|---|---|
PUBLIC_SANITY_VISUAL_EDITING_ENABLED | true | Enables draft perspective, stega encoding, live updates, and overlay |
PUBLIC_SANITY_VISUAL_EDITING_ENABLED | false (default) | Static build mode — queries use the published perspective |
SANITY_API_READ_TOKEN | your token | Required when Visual Editing is true |
Visual Editing workflow
When Visual Editing is enabled,[...slug].astro skips the static fetch path entirely and renders a <SanityPageContent server:defer> server island instead. The island fetches fresh draft data on every SSR request, so the Presentation tool always sees the latest unpublished changes.