How to create working document edit links in custom Sanity Studio v2 desk structure views?

12 replies
Last updated: Nov 29, 2025
If I have a custom document view in my desk structure, what's the best way to generate a working link from the depicted markup to the actual in-Studio edit screen in v2?
I have the ID and just leave it a relative address, and it looks
just like the real address if I were to get there by browsing panes. But if I click it, it either gets there after a huge refresh of the whole Studio page's tab, or it becomes unresponsive.
I did search and read through things first before asking but perhaps I've overlooked something. I saw
user H
do something like that in his pretend cake shop at the conference but I'm not sure how that works.

Note: EDITED because I accidentally called it JSON view because the documentation example was saturated into my brain
AI Update

For creating working links to document edit screens in Sanity Studio v2 from custom document views, you'll want to use the IntentLink component rather than plain relative links. This is the proper way to navigate within the Studio without causing full page refreshes or unresponsive behavior.

The IntentLink component from part:@sanity/base/router handles Studio navigation properly by working with the internal state management system. Here's how to use it:

import { IntentLink } from 'part:@sanity/base/router'

// In your component
<IntentLink
  intent="edit"
  params={{ id: documentId, type: documentType }}
>
  Click to edit
</IntentLink>

This generates URLs that look like:

http://localhost:3333/intent/edit/id=4497efe3-8ab6-4e55-872e-b1ef9577cc07;type=paletteColor/

When you use regular <a> tags with relative paths like /desk/paletteColor-unsorted;d27d5d4e-5faf-4a4c-b25f-0213e2ea492c, the browser treats it as a full page navigation. This causes:

  • Complete Studio page reloads (that "huge refresh" you're experiencing)
  • Loss of internal state tracking
  • Potential unresponsiveness as the Studio tries to reinitialize

The Studio maintains complex state for the desk structure, panes, and document editing sessions. IntentLink preserves all of this by using the internal router.

Complete Example

Here's a more complete example showing IntentLink in context:

import React from 'react'
import { IntentLink } from 'part:@sanity/base/router'
import Preview from 'part:@sanity/base/preview'
import schema from 'part:@sanity/base/schema'

const MyCustomView = ({ documents }) => {
  return (
    <div>
      {documents.map((doc) => {
        const schemaType = schema.get(doc._type)
        return (
          <IntentLink
            key={doc._id}
            intent="edit"
            params={{ id: doc._id, type: doc._type }}
          >
            <Preview value={doc} type={schemaType} />
          </IntentLink>
        )
      })}
    </div>
  )
}

This pattern is used throughout Sanity's own components (like in the backlinks recipe) and provides smooth, stateful navigation within the Studio.

Note: If you've migrated to Studio v3, the approach has changed - you'd use the router from sanity/router instead. But for v2, IntentLink is the way to go!

Show original thread
12 replies

Sanity – Build the way you think, not the way your CMS thinks

Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.

Was this answer helpful?