Everything is accessed through a single import:
import { EditorFocusScopeProvider } from '@react-email/editor/ui';
Wrap your editor UI with EditorFocusScopeProvider when you need focus-aware
portals outside the built-in Inspector. The provider tracks registered scopes
from EditorFocusScope and keeps
the editor’s focus and blur behavior in sync across them.
EditorFocusScopeProvider must be rendered inside the current editor context so
it can access the active editor instance.
Inspector.Root itself uses the
EditorFocusScope by default, so
the Inspector handles the editor’s focus idiomatically and reliably. If you
are only using the Inspector, you usually do not need to render this provider
manually.
Example
import {
EditorFocusScope,
EditorFocusScopeProvider,
} from '@react-email/editor/ui';
import { EditorContent, EditorContext, useEditor } from '@tiptap/react';
import * as Popover from '@radix-ui/react-popover';
export function MyEditor() {
const editor = useEditor({
extensions,
content,
});
return (
<EditorContext.Provider value={{ editor }}>
<EditorFocusScopeProvider clearSelectionOnBlur={false}>
<EditorContent editor={editor} />
<Popover.Root>
<Popover.Trigger type="button">Theme presets</Popover.Trigger>
<Popover.Portal>
<EditorFocusScope>
<Popover.Content sideOffset={8}>
<button type="button">Apply preset</button>
</Popover.Content>
</EditorFocusScope>
</Popover.Portal>
</Popover.Root>
</EditorFocusScopeProvider>
</EditorContext.Provider>
);
}
Use EditorFocusScope for each
portaled surface that should still count as being inside the editor UI.
Props
The editor UI subtree that should share focus tracking.
When focus leaves every registered scope, clear the current selection as part
of blur handling. Set this to false if you want to preserve the selection
when the editor truly loses focus.