> ## Documentation Index
> Fetch the complete documentation index at: https://vuemail.dev/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Inspector

> Add a contextual sidebar for document, node, and text editing.

The Inspector is a sidebar that provides a way to inspect and edit the email's properties. From the Inspector, you can edit document, node, and text properties such as colors, fonts, and padding.

View a minimal example of the Inspector at the [Standalone Editor Inspector](https://vuemail.dev/editor/standalone-editor-inspector) demo page.

## Quick start

Add [EmailTheming](https://vuemail.dev/docs/editor/api-reference/theming-api.md) and render
`Inspector.Root` next to the editor content. The inspector switches
automatically between document, node, and text controls based on the current
selection.

```vue theme={null}
<script setup lang="ts">
import { EditorProvider } from '@vuemaildev/editor';
import { StarterKit } from '@vuemaildev/editor/extensions';
import { EmailTheming } from '@vuemaildev/editor/plugins';
import { Inspector } from '@vuemaildev/editor/ui';
import '@vuemaildev/editor/themes/default.css';

const extensions = [StarterKit, EmailTheming];
</script>

<template>
  <div class="flex min-h-0 overflow-hidden">
    <EditorProvider
      :extensions="extensions"
      :content="content"
      editor-class="flex-1 min-w-0 p-4"
    >
      <Inspector.Root class="w-60 shrink-0 border-l p-4">
        <Inspector.Breadcrumb />
        <Inspector.Document />
        <Inspector.Node />
        <Inspector.Text />
      </Inspector.Root>
    </EditorProvider>
  </div>
</template>
```

`EditorProvider` renders the editor content and its children as siblings, so the inspector sits next to
the editor in the flex layout.

Click the editor background to edit document-level styles. Click a node, such as a button, to edit its properties. Select text to switch to text controls.

> [!TIP]
>
> You can [customize the inspector](#customizing-the-inspector) with scoped slots. The default panels can also be styled using [CSS variables and `data-re-*` selectors](https://vuemail.dev/docs/editor/features/styling#inspector).

## Using with EmailEditor

If you use the standalone `EmailEditor` component, pass the inspector as a child instead of setting up `EditorProvider` manually.

```vue theme={null}
<script setup lang="ts">
import { EmailEditor } from '@vuemaildev/editor';
import { Inspector } from '@vuemaildev/editor/ui';
</script>

<template>
  <div class="flex" :style="{ height: '600px' }">
    <EmailEditor
      content="<h1>Hello</h1><p>Click any element to inspect it.</p>"
      class="flex-1 min-w-0 overflow-y-auto p-4"
    >
      <Inspector.Root class="w-60 shrink-0 border-l p-4 overflow-y-auto">
        <Inspector.Breadcrumb />
        <Inspector.Document />
        <Inspector.Node />
        <Inspector.Text />
      </Inspector.Root>
    </EmailEditor>
  </div>
</template>
```

`EmailEditor` includes `EmailTheming` in its default extensions, so the
[required extension](#required-extension) is already covered.

> [!TIP]
>
> Children of `EmailEditor` render as DOM siblings of the editor content area,
> so flex layouts work naturally.

## Required extension

`Inspector.Root` requires the [EmailTheming](https://vuemail.dev/docs/editor/api-reference/theming-api.md)
extension. Without it, the inspector cannot resolve theme defaults or apply
document-level style changes, and it will error.

```ts theme={null}
import { StarterKit } from '@vuemaildev/editor/extensions';
import { EmailTheming } from '@vuemaildev/editor/plugins';

const extensions = [StarterKit, EmailTheming];
```

## Zero-config defaults

When you render the three default panels without children, the inspector gives
you a ready-made sidebar with sensible controls for common editing tasks using
the standard HTML elements like input and select.

| Component | When it appears | Default behavior |
| - | - | - |
| `Inspector.Document` | When the editor is not focused on a specific node or text selection | Controls global theme-backed styles like page background and container settings |
| `Inspector.Node` | When a node is focused or selected | Adapts to the current node type and shows sections like attributes, size, typography, padding, border, and background |
| `Inspector.Text` | When text is selected | Shows text formatting, alignment, typography, and link color controls |

This gives you a complete inspector with no custom UI code required.

## Breadcrumb navigation

Use `Inspector.Breadcrumb` to show the current path from the document root down
to the focused node, and let users jump back up the hierarchy.

```vue theme={null}
<Inspector.Root>
  <Inspector.Breadcrumb v-slot="{ segments }">
    <button
      v-for="(segment, index) in segments"
      :key="index"
      type="button"
      @click="segment.focus()"
    >
      {{ segment.node.nodeType }}
    </button>
  </Inspector.Breadcrumb>

  <Inspector.Document />
  <Inspector.Node />
  <Inspector.Text />
</Inspector.Root>
```

To use the default breadcrumb rendering:

```vue theme={null}
<Inspector.Root>
  <Inspector.Breadcrumb />
  <Inspector.Document />
  <Inspector.Node />
  <Inspector.Text />
</Inspector.Root>
```

## Customizing the Inspector

The Inspector.Root itself keeps track of what is meant to be inspected. This can either be the document, a node, or a text selection.

The `<Inspector.Document>`, `<Inspector.Node>`, and `<Inspector.Text>` components
are convenience components that only render when their respective target is active.
Give them a default slot to replace their default UI: the slot receives the context of what's inspected.

### Inspector.Document

```vue theme={null}
<Inspector.Root>
  <Inspector.Document v-slot="{ findStyleValue, setGlobalStyle }">
    <input
      type="color"
      :value="findStyleValue('body', 'backgroundColor')"
      @input="
        setGlobalStyle(
          'body',
          'backgroundColor',
          ($event.target as HTMLInputElement).value,
        )
      "
    />
  </Inspector.Document>
</Inspector.Root>
```

**findStyleValue** `(classReference, property) =\> string | number`

Looks up the current value for a document-level style property.

**setGlobalStyle** `(classReference, property, value) =\> void`

Updates an existing style entry or adds a new one.

**batchSetGlobalStyle** `(changes) =\> void`

Applies multiple document-level style updates in one call.

Internally, [EmailTheming](https://vuemail.dev/docs/editor/api-reference/theming-api.md) keeps track of the document-level styles through a
large JSON array with entries for each selector and style property.

### Inspector.Node

```vue theme={null}
<Inspector.Root>
  <Inspector.Node v-slot="{ nodeType, getStyle, setStyle, getAttr, setAttr }">
    <div>{{ nodeType }}</div>
    <input
      type="text"
      :value="String(getAttr('alt') ?? '')"
      @input="setAttr('alt', ($event.target as HTMLInputElement).value)"
    />
    <input
      type="color"
      :value="String(getStyle('backgroundColor') ?? '')"
      @input="setStyle('backgroundColor', ($event.target as HTMLInputElement).value)"
    />
  </Inspector.Node>
</Inspector.Root>
```

**nodeType** `string`

The currently focused node type, such as `image`, `button`, or `section`.

**getStyle** `(prop) =\> string | number | undefined`

Reads a resolved style value from the active node.

**setStyle** `(prop, value) =\> void`

Updates a single inline style on the active node.

**batchSetStyle** `(changes) =\> void`

Applies multiple style updates in one call.

**getAttr** `(name) =\> unknown`

Reads a node attribute such as `alt`, `href`, or `width`.

**setAttr** `(name, value) =\> void`

Updates a node attribute.

**themeDefaults** `Record\<string, string | number | undefined\>`

The resolved theme defaults for the current node before inline overrides.

**presetColors** `string[]`

Colors collected from the current document that can be reused in custom controls.

**nodePos** `\{ pos: number; inside: number \}`

The ProseMirror position metadata for the focused node.

### Inspector.Text

```vue theme={null}
<Inspector.Root>
  <Inspector.Text v-slot="{ marks, toggleMark, alignment, setAlignment }">
    <button type="button" @click="toggleMark('bold')">
      {{ marks.bold ? 'Unbold' : 'Bold' }}
    </button>
    <button type="button" @click="setAlignment('center')">
      {{ alignment === 'center' ? 'Centered' : 'Center' }}
    </button>
  </Inspector.Text>
</Inspector.Root>
```

**marks** `Record\<string, boolean\>`

A map of active text marks. These include `bold`, `italic`, `underline`, `strike`, and `code`.

**toggleMark** `(mark) =\> void`

Toggles a text mark on the current selection.

**alignment** `string`

The current alignment of the parent text block.

**setAlignment** `(value) =\> void`

Updates the alignment of the parent text block.

**linkHref** `string`

The current link URL when the selection is inside a link.

**linkColor** `string`

The resolved color for the active link.

**setLinkColor** `(color) =\> void`

Updates the color of the active link.

**isLinkActive** `boolean`

Whether the current text selection is inside a link.

**getStyle** `(prop) =\> string | number | undefined`

Reads a resolved style value from the parent text block.

**setStyle** `(prop, value) =\> void`

Updates a style on the parent text block.

**presetColors** `string[]`

Colors collected from the current document that can be reused in custom controls.

## Using portals without losing inspector focus

If your custom inspector uses portaled UI like reka-ui's `Select`, `Popover`, or
dropdown content, moving focus into that portal can make the editor think it
blurred. That can switch the active inspector target or clear the current text
selection.

Wrap the portaled content with
[`EditorFocusScope`](https://vuemail.dev/docs/editor/api-reference/ui/editor-focus-scope) so focus
inside the portal is still treated as part of the editor UI.

```vue theme={null}
<script setup lang="ts">
import { EditorFocusScope, Inspector } from '@vuemaildev/editor/ui';
import {
  SelectContent,
  SelectItem,
  SelectItemText,
  SelectPortal,
  SelectRoot,
  SelectTrigger,
  SelectValue,
  SelectViewport,
} from 'reka-ui';
</script>

<template>
  <Inspector.Node v-slot="{ getAttr, setAttr }">
    <SelectRoot
      :model-value="String(getAttr('alignment') ?? 'left')"
      @update:model-value="(value) => setAttr('alignment', value)"
    >
      <SelectTrigger>
        <SelectValue />
      </SelectTrigger>

      <SelectPortal>
        <EditorFocusScope>
          <SelectContent>
            <SelectViewport>
              <SelectItem value="left">
                <SelectItemText>Left</SelectItemText>
              </SelectItem>
              <SelectItem value="center">
                <SelectItemText>Center</SelectItemText>
              </SelectItem>
              <SelectItem value="right">
                <SelectItemText>Right</SelectItemText>
              </SelectItem>
            </SelectViewport>
          </SelectContent>
        </EditorFocusScope>
      </SelectPortal>
    </SelectRoot>
  </Inspector.Node>
</template>
```

`Inspector.Root` already uses
[`EditorFocusScope`](https://vuemail.dev/docs/editor/api-reference/ui/editor-focus-scope) by default to
handle the editor's focus idiomatically and reliably. Inside a custom inspector
you usually only need to add `EditorFocusScope` around the portaled content.
The same pattern works for other portaled reka-ui components, not just `Select`.

## Reusing built-in sections

You can also mix custom layouts with the built-in section components, which take the context of
`Inspector.Node` as props.

```vue theme={null}
<Inspector.Node v-slot="context">
  <Inspector.Size v-bind="context" />
  <Inspector.Padding v-bind="context" />
  <Inspector.Border v-bind="context" />
</Inspector.Node>
```

Available section components:

| Component | Description |
| - | - |
| `Inspector.Attributes` | Editable node attributes using field types inferred from the attribute schema |
| `Inspector.Background` | Background color control for nodes |
| `Inspector.Border` | Border width, style, color, and radius controls |
| `Inspector.Link` | Link URL and link color controls for active text links |
| `Inspector.Padding` | Four-sided padding editor |
| `Inspector.Size` | Width and height controls |
| `Inspector.Typography` | Color, size, line height, marks, and alignment controls |

## Examples

See the inspector in action with runnable examples:

> **[Inspector — Defaults](https://vuemail.dev/editor/inspector-defaults)**
>
> Zero-config document, node, and text inspectors.

> **[Inspector — Composed](https://vuemail.dev/editor/inspector-composed)**
>
> Showing how to use default sections and add a custom one.

> **[Inspector — Fully Custom](https://vuemail.dev/editor/inspector-custom)**
>
> Fully custom inspector UI built from scoped slots.

> **[Standalone Editor — Inspector](https://vuemail.dev/editor/standalone-editor-inspector)**
>
> Inspector sidebar with the standalone EmailEditor component.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.