Navigate the Dashboard
Keep your app's router in sync with the Dashboard and link to other apps, Studios, and documents.
The Dashboard owns the browser URL. Your app's routes live under the app's own path in the Dashboard, and links to other apps or Studios go through the Dashboard's router.
Keep your router in sync
Pass useNavigate a callback when your app has its own router. The callback receives the navigations the Dashboard asks your app to perform, such as the back button or a link into your app, and the function it returns reports your app's own navigations so the browser URL follows. Render this component inside your router and SanityApp:
import {useNavigate} from '@sanity/sdk-react/dashboard'
import {useEffect} from 'react'
import {useLocation, useNavigate as useRouterNavigate} from 'react-router'
export function DashboardNavigationSync() {
const routerNavigate = useRouterNavigate()
const {pathname, search, hash} = useLocation()
const navigate = useNavigate(({path, type}) => {
routerNavigate(path, {replace: type === 'replace'})
})
useEffect(() => {
navigate({path: `${pathname.slice(1)}${search}${hash}`})
}, [navigate, pathname, search, hash])
return null
}path is relative to your app's route, with no leading slash, and can include a query string and hash. Pass type: 'replace' to replace the current history entry instead of adding one.
Navigate to another app
Build the destination with urlFor, then call the navigate function with scope: 'dashboard'. A component that only sends the user somewhere doesn't need a callback. Calling useNavigate() without one needs @sanity/sdk-react 3.9.0 or later:
import {urlFor, useNavigate} from '@sanity/sdk-react/dashboard'
export function OpenApp({applicationId}: {applicationId: string}) {
const navigate = useNavigate()
const url = urlFor.applications(applicationId).url()
return (
<button type="button" onClick={() => navigate({path: url, scope: 'dashboard'})}>
Open app
</button>
)
}urlFor also builds URLs with studios(appId), mediaLibrary(), canvas(), and home(). Call .url() to get the string. To open a document in a Studio, use useNavigateToStudioDocument instead.
Render a link
For a real link, set href to the urlFor URL so users can open it in a new tab, and navigate through the Dashboard on a plain click:
import {useNavigate} from '@sanity/sdk-react/dashboard'
import type {MouseEvent, ReactNode} from 'react'
export function DashboardLink({url, children}: {url: string; children: ReactNode}) {
const navigate = useNavigate()
function handleClick(event: MouseEvent<HTMLAnchorElement>) {
if (event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey) return
event.preventDefault()
navigate({path: url, scope: 'dashboard'})
}
return (
<a href={url} onClick={handleClick}>
{children}
</a>
)
}Open a Studio document
useNavigateToStudioDocument finds a Studio for the document's project and dataset and opens the document there. The hook suspends while it looks up the Studio, so wrap the component in Suspense:
import {type DocumentHandle} from '@sanity/sdk-react'
import {useNavigateToStudioDocument} from '@sanity/sdk-react/dashboard'
import {Suspense} from 'react'
function EditButtonInner({documentHandle}: {documentHandle: DocumentHandle}) {
const {navigateToStudioDocument} = useNavigateToStudioDocument(documentHandle)
return (
<button type="button" onClick={navigateToStudioDocument}>
Edit in Studio
</button>
)
}
export function EditButton({documentHandle}: {documentHandle: DocumentHandle}) {
return (
<Suspense
fallback={
<button type="button" disabled>
Edit in Studio
</button>
}
>
<EditButtonInner documentHandle={documentHandle} />
</Suspense>
)
}