Visual Editing with Nuxt
Get started with Sanity Visual Editing in a new or existing Nuxt application.
Following this guide will enable you to:
- Render overlays in your application, allowing content editors to jump directly from Sanity content to its source in Sanity Studio.
- Edit your content and see changes reflected in an embedded preview of your application in Sanity’s Presentation tool.
- Provide instant updates and seamless switching between draft and published content.
Prerequisites
- A Sanity project with a hosted or embedded Studio. Read more about hosting the Studio.
- A Nuxt application with SSR. Follow the Nuxt installation guide to set one up.
Nuxt application setup
The following steps should be performed in your Nuxt application.
Install dependencies
Install the Sanity module, which provides your application with data fetching and Visual Editing capabilities.
npx nuxi@latest module add sanity
pnpm dlx nuxi@latest module add sanity
yarn dlx nuxi@latest module add sanity
bunx nuxi@latest module add sanity
Environment variables
Create a .env file in your application’s root directory to provide Sanity-specific configuration.
You can use Manage to find your project ID and dataset, and to create a token with Viewer permissions which will be used to fetch preview content.
The URL of your Sanity Studio will depend on where it is hosted or embedded.
# .env # Public SANITY_PROJECT_ID="YOUR_PROJECT_ID" SANITY_DATASET="YOUR_DATASET" SANITY_STUDIO_URL="YOUR_STUDIO_URL" # Private SANITY_VIEWER_TOKEN="YOUR_VIEWER_TOKEN"
Application setup
Sanity module
Configure the Sanity module to handle fetching data from Content Lake.
Configuring the stega option enables automatic overlays for basic data types when preview mode is enabled. Read more about how stega works.
// nuxt.config.ts
export default defineNuxtConfig({
modules: ['@nuxtjs/sanity'],
sanity: {
projectId: process.env.SANITY_PROJECT_ID,
dataset: process.env.SANITY_DATASET,
apiVersion: '2026-07-01',
visualEditing: {
token: process.env.SANITY_VIEWER_TOKEN,
studioUrl: process.env.SANITY_STUDIO_URL,
stega: true
}
}
})VisualEditing component props
The <VisualEditing /> component rendered by the @nuxtjs/sanity module accepts additional props introduced in @sanity/visual-editing 5.5.0. Make sure your project uses version 5.5.0 or later.
For example, use onSuspiciousStega to log reports of stega found in unsafe DOM placements. The module serializes the callback into the build, so it must be self-contained. Don't reference imports or variables defined outside the function body.
// nuxt.config.ts
export default defineNuxtConfig({
modules: ['@nuxtjs/sanity'],
sanity: {
projectId: process.env.SANITY_PROJECT_ID,
dataset: process.env.SANITY_DATASET,
apiVersion: '2026-07-01',
visualEditing: {
token: process.env.SANITY_VIEWER_TOKEN,
studioUrl: process.env.SANITY_STUDIO_URL,
stega: true,
// Report stega found in unsafe DOM placements
onSuspiciousStega: (reports) => {
for (const report of reports) {
console.warn(`Stega found in ${report.kind}`, report)
}
},
}
}
})Performance note
The onSuspiciousStega callback performs an initial full DOM audit (TreeWalker and MutationObserver), then incremental idle-time checks as the DOM changes. It is intended for debugging rather than production use.
keepStegaOnCopy
boolean
Optional. Default:
false. By default,<VisualEditing />intercepts copy events and removes stega encoding from bothtext/plainandtext/htmlclipboard payloads so users do not get invisible characters when copying text from the preview page. Copies without stega are left untouched. SetkeepStegaOnCopytotrueto disable this behavior.onSuspiciousStega
(reports: SuspiciousStegaReport[]) => void
Optional. Opt-in callback that reports stega found in unsafe DOM placements: element attributes (
class,id,href,src,style,data-*, and others), inside<head>(title,meta[content]), in<script>or<style>text content (including JSON-LD), intextareaform values, or in the page URL. Each report includeskind,element(if applicable),attribute(if applicable),value,cleaned, and, when the encoded value resolves to a Sanity node,sanity. Performs an initial full DOM audit (TreeWalker and MutationObserver), then incremental idle-time checks. Intended for debugging rather than production use.
Rendering pages
First, set up the queries you will use to fetch data from Content Lake.
// queries.ts
export type PageResult = { title: string }
export const pageQuery = /* groq */`*[_type == "page"][0]{title}`// pages/index.vue
<script setup lang="ts">
import {pageQuery, type PageResult} from '../queries'
const {data, pending} = await useSanityQuery<PageResult>(pageQuery)
</script>
<template>
<div v-if="pending">Loading...</div>
<h1 v-else>{{ data?.title }}</h1>
</template>Studio setup
To set up the Presentation Tool in your Studio, import the tool from sanity/presentation, add it to your plugins array, and configure previewUrl with an initial preview URL and the endpoint used to enable preview mode.
We similarly recommend using environment variables loaded via a .env file to support development and production environments.
// sanity.config.ts
import {defineConfig} from 'sanity'
import {presentationTool} from 'sanity/presentation'
export default defineConfig({
// ... project configuration
plugins: [
presentationTool({
previewUrl: {
initial: process.env.SANITY_STUDIO_PREVIEW_ORIGIN,
previewMode: {
enable: '/preview/enable',
},
}
}),
// ... other plugins
],
})Optional extras
Adding data attributes
useSanityQuery also returns an encodeDataAttribute helper method for generating data-sanity attributes. These attributes give you direct control over rendering overlays in your application, and are especially useful if not using stega encoding.
// pages/index.vue
<script setup lang="ts">
import {pageQuery, type PageResult} from '../queries'
const {data, pending, encodeDataAttribute} = await useSanityQuery<PageResult>(pageQuery)
</script>
<template>
<div v-if="pending">Loading...</div>
<h1 v-else :data-sanity="encodeDataAttribute(['title'])">{{ data?.title }}</h1>
</template>Next steps
You now have a Nuxt application that renders overlays, updates content instantly, and previews drafts in the Presentation Tool. To keep going, learn more about configuring the Presentation Tool, customizing overlays, and how stega encoding works.