👀 Our most exciting product launch yet 🚀 Join us May 8th for Sanity Connect

Studio Tools

A tool is a top-level view in the Sanity Studio application that you can access through its menu bar.

A tool is a top-level view in the Sanity Studio application that you can access through its menu bar. The most common and built-in tool for the Studio is the Structure tool, which lets you browse and edit documents. You can install tools with plugins or create your own. Tools are tied to the Studio’s routing. That means that tools can be accessed through URLs.

Tools are great for custom dashboards and user interfaces for exploring and interacting with content. Plugins can also export tools. For example, the Media plugin will add a tool to browse all your assets, and the Vision plugin lets you run GROQ queries in your Studio.

Basic configuration

You can add a custom tool by adding its configuration object to the tools array in the studio configuration. A tool needs to have a title, name, icon, and component defined. The title controls what appears in the toolbar, while the name controls the URL segment that the tool routes to.

// sanity.config.tsx
import {defineConfig} from 'sanity'
import {structureTool} from 'sanity/structure'
import {Card, Text} from '@sanity/ui'
import {DashboardIcon} from '@sanity/icons'
import {schemaTypes} from './schemas'

const myCustomTool = () => {
  return {
    title: 'My Custom Tool',
    name: 'my-custom-tool', // localhost:3333/my-custom-tool
    icon: DashboardIcon,
    component: (props) => (
      <Card padding={4}>
        <Text>My custom tool!</Text>
      </Card>
    ),
  }
}

export default defineConfig({
  name: 'default',
  title: 'Studio with custom tool',
  projectId: 'your-project-id',
  dataset: 'production',
  plugins: [structureTool()],
  tools: [myCustomTool()],
  schema: {
    types: schemaTypes,
  },
})

Protip

If you want to use @sanity/ui and @sanity/icons for your own tools, remember to install them as dependencies in your project:

npm install @sanity/ui @sanity/icons

Ordering of tools

Tools are ordered as they are added in the tools array, followed by tools that are added via plugins in the plugins array. A tool within a plugin can override the default ordering via the studio.components.toolMenu.tools property in the plugin config. And likewise, you can edit this order by accessing this property yourself in the config. In the example below, we make sure that the Structure tool always comes first in the menu:

// sanity.config.js
export default defineConfig({
  name: 'default',
  title: 'test',
  projectId: 'kh2fp3g7',
  dataset: 'production',
  studio: {
    components: {
      toolMenu: (props) => {
        const {tools, renderDefault} = props
        const structureTool = tools.find(({name}) => name == 'desk')
        const otherTools = tools.filter(({name}) => name != 'desk')

        if (!structureTool) {
          return renderDefault(props)
        }

        return props.renderDefault({
          ...props,
          tools: [structureTool, ...otherTools],
        })
      },
    },
  },
  plugins: [structureTool()],
  tools: [myCustomTool, myOtherCustomTool],
  schema: {
    types: schemaTypes,
  },
})

TypeScript

If you're building with TypeScript, then you can use the built-in Tool type from the studio package, as well as the ComponentType from the react package. You can also extend these to support custom options you might have for your tool:

// myCustomTool.tsx
import type {ComponentType} from 'react'
import {type Tool} from 'sanity'
import {Card, Text, Stack} from '@sanity/ui'

export interface myCustomToolOptions {
   customString?: string
}

export interface myCustomToolProps<Options = any> {
  component: ComponentType<{
      tool: Tool<myCustomToolOptions>
  }>
}

export const myCustomTool = (options: myCustomToolOptions | void) => {
  return {
    title: 'My Custom Tool',
    name: 'my-custom-tool', // localhost:3333/my-custom-tool
    icon: DashboardIcon,
    component: () => (
      <Card padding={4}>
        <Stack>
          <Text>My custom tool!</Text>
          <Text>{options?.customString}</Text>
        </Stack>
      </Card>
    ),
  }
}

Was this article helpful?