Documentation Index
Fetch the complete documentation index at: https://react.email/docs/llms.txt
Use this file to discover all available pages before exploring further.
Everything is accessed through a single import:
import {
EditorFocusScope,
} from '@react-email/editor/ui';
The FocusScopes extension, included by default in StarterKit, keeps the
editor’s focus and blur behavior in sync across registered surfaces. Wrap each
custom portaled surface that should still count as being inside the editor UI
with EditorFocusScope.
Inspector.Root, built-in bubble menus, and slash commands already register
themselves. Inside custom portaled UI, you usually only add
EditorFocusScope around the portaled content.
EditorFocusScopeProvider
EditorFocusScopeProvider is deprecated. Focus tracking moved to the
FocusScopes extension, which is included by default in StarterKit, but the
provider still installs the same tracking plugin for editors that do not use
StarterKit.
Example
import { StarterKit } from '@react-email/editor/extensions';
import { EditorFocusScope } 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: [StarterKit.configure()],
content,
});
return (
<EditorContext.Provider value={{ editor }}>
<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>
</EditorContext.Provider>
);
}
Use EditorFocusScope for each portaled surface that should still count as
being inside the editor UI.
Props
Deprecated. Used only by the provider’s fallback plugin. Prefer configuring
FocusScopes in StarterKit instead.
EditorFocusScope
Use EditorFocusScope around portaled UI like Radix Select.Content,
Popover.Content, or dialog content so moving focus into that portal is still
treated as staying inside the editor UI.
EditorFocusScope registers with the editor’s FocusScopes extension. If the
extension is not present, it renders its children unchanged.
Example
import { EditorFocusScope, Inspector } from '@react-email/editor/ui';
import * as Select from '@radix-ui/react-select';
<Inspector.Node>
{({ getAttr, setAttr }) => (
<Select.Root
value={String(getAttr('alignment') ?? 'left')}
onValueChange={(value) => setAttr('alignment', value)}
>
<Select.Trigger>
<Select.Value />
</Select.Trigger>
<Select.Portal>
<EditorFocusScope>
<Select.Content>
<Select.Viewport>
<Select.Item value="left">
<Select.ItemText>Left</Select.ItemText>
</Select.Item>
<Select.Item value="center">
<Select.ItemText>Center</Select.ItemText>
</Select.Item>
<Select.Item value="right">
<Select.ItemText>Right</Select.ItemText>
</Select.Item>
</Select.Viewport>
</Select.Content>
</EditorFocusScope>
</Select.Portal>
</Select.Root>
)}
</Inspector.Node>
If you are building a focus-aware editor shell without StarterKit, add the
FocusScopes extension and then use EditorFocusScope for each portaled
surface.
Props
The element or subtree to register as an additional editor focus scope. Wrap
the portaled container that receives focus.