Visual Editing

Visual Editing with SvelteKit

Get started with Sanity Visual Editing in a new or existing SvelteKit 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.
  • Optional: 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 here.
  • A SvelteKit application using Svelte 5 with SSR. Follow this guide to set one up.

SvelteKit application setup

The following steps should be performed in your SvelteKit application.

Install dependencies

Install the Sanity SvelteKit package that will provide your application with data fetching and Visual Editing capabilities.

Set environment variables

Create a .env file in your application’s root directory to provide Sanity-specific configuration.

In the project management area, find your project ID and dataset, and 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.

Sanity client

Create a Sanity client instance to handle fetching data from Content Lake.

Configuring the stega option enables automatic overlays for basic data types when preview mode is enabled. You can read more about how stega works here.

Create a server-only Sanity client instance using the Viewer token and client created above. This will be used to fetch draft content when in preview mode.

Preview mode

Preview mode allows authorized content editors to view and interact with draft content.

In the server hooks file, sequence the handlePreviewMode handle function, which adds preview mode to your application.

The handle function implemented above adds a sanity property to the locals object, exposing the status of preview mode on the server. The server layout file lets you expose this value for use in a Svelte layout file.

TypeScript

Render the PreviewMode wrapper component in the Svelte layout file to ensure the correct preview context is available in child components.

Rendering pages

First, define the GROQ queries you will use to fetch data from Content Lake. In the following example we are fetching the title of the first document of type page returned.

Next, define a load function that uses your query to fetch and return data.

When fetching content using the Sanity client in an application that implements visual editing using stega, make sure to set stega to false when preview mode is disabled.

The load function’s return value will be available in the corresponding .svelte file via the data prop. Use a $derived rune to ensure the page remains reactive.

You should now see the page render with the correct page title, confirming that your query and data binding are working as expected.

Enable Visual Editing

The <VisualEditing> component handles rendering overlays, enabling click to edit, and refreshing pages in your application when content changes.

Providing the component with the current preview mode status ensures these features are only enabled for content editors, while your application remains unchanged for regular users.

That's it for setup in your Svelte application for now. In the next section we'll enable Visual Editing in your studio project!

Studio setup

To set up Presentation tool in your studio, import the tool from sanity/presentation, add it to your plugins array, and configure previewUrl, passing the origin of your application and endpoints to enable and disable preview mode.

At this point, you should have Visual Editing set up in your SvelteKit app and connected to your Sanity Studio. In the Presentation tool, you can view your application in an embedded preview and click content to edit in context. The next steps introduce advanced features like faster content updates and perspective switching.

Using Loaders (optional)

Loaders enhance the Visual Editing experience by providing faster content updates and perspective switching.

The Query Loader offers instant updates when previewing content in the Presentation tool, while the Live Loader connects to Sanity’s Live Content API to deliver continuous updates to both editors using Presentation tool and end users.

Loaders

Query Loader

The Query Loader provides instant content updates and perspective switching when using the Presentation tool.

1. Update server hooks

Update your server hooks file to call setServerClient and sequence the handleQueryLoader handle function. This sets up the loadQuery helper function which will be used for fetching content on the server.

2. Update layout

In the layout component, render the QueryLoader wrapper component to enable instant updates. Pass a Sanity client instance and enable the loader when preview mode is active using props.

3. Use loadQuery and useQuery

In your page's load function, you can now use the loadQuery function exposed by locals.sanity to ensure data is fetched from Content Lake with the correct perspective: draft content will be fetched if preview mode is enabled, otherwise published content is returned.

Structuring the load function's return value in this way conveniently means you can pass the data value directly to the useQuery function. useQuery returns a readable store. Prefix any references to the store with $ to access its value when deriving state.

When your application is viewed in Presentation tool, useQuery provides instant content updates and seamless switching between draft and published content.

Live Loader

The Live Loader provides content updates using the Live Content API both in the Presentation tool (draft and published content) and to end users of your application (published content only).

1. Update server hooks

Update your server hooks file to sequence the handleLiveLoader handle function. This sets up the sanityFetch helper function which will be used for fetching content on the server.

The serverToken is used to fetch draft content on the server and so must have permissions to query draft documents. The browserToken allows live previewing draft content outside of the Presentation tool.

The same token can be used as both browserToken and serverToken, as the browserToken is only shared with the browser when preview mode is enabled.

2. Update layout

Update the server layout file to expose the browserToken and previewPerspective properties added by handleLiveLoader.

In the layout component, render the LiveLoader wrapper component to enable live updates. Unlike other components exported by @sanity/sveltekit, LiveLoader doesn't accept an enabled prop, as it provides live updates to both content editors and end users.

3. Use sanityFetch

Import and use sanityFetch to fetch data using the Live Content API. The event object provided by a load function should be passed as the first argument.

The corresponding Svelte page will receive the result of the query. Use a $derived rune to ensure the page remains reactive.

Advanced features (optional)

Adding data attributes

Along with the createDataAttribute function exported by @sanity/sveltekit, when using the Query Loader, useQuery 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.

Context functions and conditional rendering

Your application might need to conditionally render elements in preview mode, for example to notify content editors that they are viewing draft content, or to provide a mechanism for disabling preview mode.

@sanity/sveltekit exports several helper functions which return useful context for this purpose:

getLoader() - Returns which loader is currently in use: 'live', 'query' or undefined.

getIsPreviewing() - Returns true if preview mode is enabled, otherwise returns false. Available in descendants of the PreviewMode component.

The example below shows how to use this function to implement a component for disabling preview mode, and could be added to your +layout.svelte file.

getPerspective() - Returns the current perspective. Available in descendants of the LiveLoader component.

getEnvironment() - Returns the currently detected preview environment. Available in descendants of the LiveLoader component.

TypeScript: event.locals

The handler functions referenced in this guide add a sanity property to SvelteKit’s event.locals object. If your application is written in TypeScript, extend the App.Locals interface with the SanityLocals type to ensure type safety.

Additionally, if you are linking to any paths that @sanity/sveltekit adds to your application—for example to create a link to disable preview mode—you may also want to overload SvelteKit's resolve function.

Was this page helpful?