> For AI agents: the complete Sanity documentation index is available at [https://www.sanity.io/docs/llms.txt](https://www.sanity.io/docs/llms.txt).

# Link to documents and tools from a custom component

Use IntentLink, StateLink, and useIntentLink from sanity/router to navigate your studio from custom React components, so links behave like links.

Sanity Studio routes every view to a URL: each tool, each pane, and each open document. When a custom component sends someone elsewhere in the studio, going through that routing is what makes the result behave like a link. Command+click opens it in a new tab, and the address is there to copy.

This guide shows how to link to a document, a new document form, or another tool from your own React components, using `IntentLink`, `StateLink`, and `useIntentLink` from `sanity/router`.

## Prerequisites

- Sanity Studio v3.0.0 or later. `IntentLink`, `StateLink`, and `useIntentLink` have all been exported from `sanity/router` since v3.0.0.
- Familiarity with writing React components.
- A custom component or tool to render the link in. See [Create a custom Studio tool](https://www.sanity.io/docs/studio/custom-studio-tool).

## Use a link, not a click handler

`IntentLink` and `StateLink` render an `<a>` element with a resolved `href`, then handle the click themselves only when the browser would have navigated in the same tab anyway. Everything else falls through to the browser:

- Command+click, Control+click, Shift+click, and Option+click
- Any click that isn't a primary-button click, including middle-click
- Any link with `target` set, such as `target="_blank"`

A `<button>` with an `onClick` handler gives you none of that. It has no `href`, so there is nothing for the browser to open in a new tab and no address to copy, and assistive technology announces it as a button rather than as a link.

> [!WARNING]
> Don't build the href by hand
> `Link` passes its `href` to the router unchanged, so the value has to be a full path that already includes your studio's base path. A studio served at `/studio` needs `/studio/vision`, not `/vision`. `IntentLink` and `StateLink` resolve the base path for you. Reach for `Link` only when you already have a resolved path, such as one returned by `useRouter().resolveIntentLink()`.

## Link to a document

`IntentLink` navigates by intent instead of by path. An `edit` intent names the document you want opened, and Studio resolves it to whichever pane in your structure handles that document type. The document opens where your editors expect it rather than in a bare editor outside your structure.

`id` is required. `type` is optional, but pass it when you know it — without it, Studio fetches the document first to find out its type.

**components/PostLink.tsx**

```tsx
import {IntentLink} from 'sanity/router'

export function PostLink(props: {postId: string; title: string}) {
  return (
    <IntentLink intent="edit" params={{id: props.postId, type: 'post'}}>
      {props.title}
    </IntentLink>
  )
}
```

If a link opens a bare editor whose pane ID starts with `__edit__`, the list you expected to catch the intent isn't declaring intent handling. See [Handle intents in the Structure Tool](https://www.sanity.io/docs/studio/handle-intents-in-structure).

## Link to a new document form

A `create` intent opens the form for a new document. `type` is required, and Studio generates the document ID. Add `template` to start the document from an initial value template.

**components/NewPostLink.tsx**

```tsx
import {IntentLink} from 'sanity/router'

export function NewPostLink() {
  return (
    <IntentLink intent="create" params={{type: 'post'}}>
      New post
    </IntentLink>
  )
}
```

## Link to another tool

Tools are reached by router state rather than by intent. `StateLink` takes the state you want and resolves it to a path, base path included. Set `tool` to the tool's `name` from your studio configuration, and clear that tool's own state so it opens at its root instead of wherever it was last left.

**components/VisionToolLink.tsx**

```tsx
import {StateLink} from 'sanity/router'

export function VisionToolLink() {
  return (
    // Clearing the tool's own state opens it at its root
    <StateLink state={{tool: 'vision', vision: undefined}}>Open the Vision Tool</StateLink>
  )
}
```

To link to the studio's root, pass `toIndex` instead of `state`. Passing both throws an error.

## Use the useIntentLink hook for custom elements

`useIntentLink` does the same resolution and the same click handling as `IntentLink`, without rendering anything itself. Reach for it when the element is already something else: a Sanity UI `Button`, a card, a table row. It returns an `href` and an `onClick`.

**components/EditPostButton.tsx**

```tsx
import {Button} from '@sanity/ui'
import {useIntentLink} from 'sanity/router'

export function EditPostButton(props: {postId: string}) {
  const {href, onClick} = useIntentLink({
    intent: 'edit',
    params: {id: props.postId, type: 'post'},
  })

  return <Button as="a" href={href} onClick={onClick} mode="ghost" text="Edit post" />
}
```

Apply both. `href` is what the browser uses for modifier-key clicks and for the link's address; `onClick` is what routes inside the studio on a plain click. Set one without the other and half the behavior goes missing.

`useStateLink` returns the same pair for router-state links, including links to another tool.

## Next steps

[Handle intents in the Structure Tool](https://www.sanity.io/docs/studio/handle-intents-in-structure)
Declare intent handling so the links you build resolve to the right pane.

[Create a custom Studio tool](https://www.sanity.io/docs/studio/custom-studio-tool)
Build the tool that renders these links.

[Custom components for Sanity Studio](https://www.sanity.io/docs/studio/intro-to-custom-studio-components)
Override parts of the Studio UI with your own React components.

[Studio API reference](https://reference.sanity.io/sanity/)
Generated reference for sanity/router, including Link, IntentLink, and useIntentLink.

