0
# Plugin System
1
2
React-specific plugin functionality that integrates Slate with React's lifecycle and event system. The plugin system enables Slate editors to work seamlessly with React components and provides React-specific enhancements.
3
4
## Capabilities
5
6
### withReact Plugin
7
8
The `withReact` function enhances a Slate editor with React-specific behaviors, DOM handling, and integration with React's component lifecycle.
9
10
```typescript { .api }
11
/**
12
* Adds React and DOM specific behaviors to the editor
13
* @param editor - Base editor to enhance
14
* @param clipboardFormatKey - Key for clipboard data format (default: 'x-slate-fragment')
15
* @returns Enhanced editor with React capabilities
16
*/
17
function withReact<T extends BaseEditor>(
18
editor: T,
19
clipboardFormatKey?: string
20
): T & ReactEditor;
21
```
22
23
**Usage Example:**
24
25
```typescript
26
import React, { useMemo } from 'react';
27
import { createEditor } from 'slate';
28
import { withReact } from 'slate-react';
29
30
const MyEditor = () => {
31
// Apply React plugin to base editor
32
const editor = useMemo(() => withReact(createEditor()), []);
33
34
// Editor now has React-specific capabilities
35
return (
36
<Slate editor={editor} initialValue={initialValue}>
37
<Editable />
38
</Slate>
39
);
40
};
41
42
// With custom clipboard format
43
const EditorWithCustomClipboard = () => {
44
const editor = useMemo(() =>
45
withReact(createEditor(), 'my-custom-format'),
46
[]
47
);
48
49
return (
50
<Slate editor={editor} initialValue={initialValue}>
51
<Editable />
52
</Slate>
53
);
54
};
55
```
56
57
### ReactEditor Interface
58
59
The `ReactEditor` interface extends `DOMEditor` from slate-dom and provides React-specific editor methods and capabilities.
60
61
```typescript { .api }
62
/**
63
* React and DOM-specific editor interface
64
* Extends DOMEditor with React-specific functionality
65
*/
66
interface ReactEditor extends DOMEditor {
67
/**
68
* Get the chunk size for performance optimization
69
* @param node - Ancestor node to get chunk size for
70
* @returns Chunk size or null if not chunked
71
*/
72
getChunkSize(node: Ancestor): number | null;
73
}
74
```
75
76
The ReactEditor interface inherits all methods from DOMEditor, including:
77
78
- DOM manipulation methods
79
- Event handling utilities
80
- Selection and range operations
81
- Node-to-DOM mapping functions
82
83
**Usage Example:**
84
85
```typescript
86
import React from 'react';
87
import { ReactEditor } from 'slate-react';
88
import { useSlateStatic } from 'slate-react';
89
90
const CustomComponent = () => {
91
const editor = useSlateStatic() as ReactEditor;
92
93
const handleClick = (element: Element) => {
94
// Use ReactEditor-specific methods
95
const domElement = ReactEditor.toDOMNode(editor, element);
96
const slateNode = ReactEditor.toSlateNode(editor, domElement);
97
98
// Check chunk size for performance optimization
99
const chunkSize = editor.getChunkSize(element);
100
if (chunkSize) {
101
console.log(`Element is chunked with size: ${chunkSize}`);
102
}
103
};
104
105
return (
106
<button onClick={() => handleClick(someElement)}>
107
Process Element
108
</button>
109
);
110
};
111
```
112
113
## Plugin Features
114
115
### React Lifecycle Integration
116
117
The `withReact` plugin integrates Slate with React's component lifecycle:
118
119
- **Component Updates**: Synchronizes editor state with React component updates
120
- **Event Handling**: Integrates DOM events with React's synthetic event system
121
- **Context Propagation**: Ensures proper context propagation throughout the editor tree
122
- **Performance Optimization**: Implements React-specific performance optimizations
123
124
### DOM Integration
125
126
React-specific DOM handling and integration:
127
128
```typescript
129
// DOM element mapping (inherited from DOMEditor)
130
const domElement = ReactEditor.toDOMNode(editor, slateNode);
131
const slateNode = ReactEditor.toSlateNode(editor, domElement);
132
133
// Range operations
134
const domRange = ReactEditor.toDOMRange(editor, slateRange);
135
const slateRange = ReactEditor.toSlateRange(editor, domRange);
136
137
// Selection handling
138
const domSelection = ReactEditor.toDOMSelection(editor, slateSelection);
139
const slateSelection = ReactEditor.toSlateSelection(editor, domSelection);
140
```
141
142
### Clipboard Integration
143
144
Enhanced clipboard functionality with React-specific handling:
145
146
```typescript
147
import { withReact } from 'slate-react';
148
149
// Default clipboard format
150
const editor = withReact(createEditor()); // Uses 'x-slate-fragment'
151
152
// Custom clipboard format
153
const customEditor = withReact(createEditor(), 'my-app-fragment');
154
```
155
156
### Event System Integration
157
158
The plugin integrates with React's event system for:
159
160
- **Keyboard Events**: Handles keyboard shortcuts and input
161
- **Mouse Events**: Manages selection and interaction
162
- **Focus Events**: Tracks editor focus state
163
- **Composition Events**: Handles IME input and composition
164
165
**Usage Example:**
166
167
```typescript
168
import React from 'react';
169
import { Editable } from 'slate-react';
170
171
const EditorWithEvents = () => {
172
return (
173
<Editable
174
onKeyDown={(event) => {
175
// React synthetic event integration
176
if (event.key === 'Enter') {
177
event.preventDefault();
178
// Handle custom enter behavior
179
}
180
}}
181
onDOMBeforeInput={(event) => {
182
// Native DOM event integration
183
console.log('Native input event:', event);
184
}}
185
/>
186
);
187
};
188
```
189
190
## Advanced Plugin Patterns
191
192
### Combining Multiple Plugins
193
194
The `withReact` plugin can be combined with other Slate plugins:
195
196
```typescript
197
import React, { useMemo } from 'react';
198
import { createEditor } from 'slate';
199
import { withReact } from 'slate-react';
200
import { withHistory } from 'slate-history';
201
202
const EditorWithPlugins = () => {
203
const editor = useMemo(() => {
204
// Apply plugins in correct order
205
return withReact(withHistory(createEditor()));
206
}, []);
207
208
return (
209
<Slate editor={editor} initialValue={initialValue}>
210
<Editable />
211
</Slate>
212
);
213
};
214
```
215
216
### Custom Plugin Creation
217
218
You can create custom plugins that work with the React plugin:
219
220
```typescript
221
import { Editor, Transforms } from 'slate';
222
import { ReactEditor } from 'slate-react';
223
224
// Custom plugin that adds React-aware functionality
225
const withCustomReactFeature = <T extends ReactEditor>(editor: T): T => {
226
const { insertText } = editor;
227
228
editor.insertText = (text: string) => {
229
// Custom logic that works with React
230
if (text === '@') {
231
// Trigger React component for mentions
232
Transforms.insertNodes(editor, {
233
type: 'mention',
234
character: '@',
235
children: [{ text: '' }]
236
});
237
return;
238
}
239
240
insertText(text);
241
};
242
243
return editor;
244
};
245
246
// Usage with React plugin
247
const editor = useMemo(() =>
248
withCustomReactFeature(withReact(createEditor())),
249
[]
250
);
251
```
252
253
### TypeScript Integration
254
255
Proper TypeScript integration with custom editor types:
256
257
```typescript
258
import { BaseEditor } from 'slate';
259
import { ReactEditor } from 'slate-react';
260
import { HistoryEditor } from 'slate-history';
261
262
// Extend editor type for TypeScript
263
type CustomEditor = BaseEditor & ReactEditor & HistoryEditor & {
264
customMethod(): void;
265
};
266
267
// Declare module for Slate TypeScript integration
268
declare module 'slate' {
269
interface CustomTypes {
270
Editor: CustomEditor;
271
Element: CustomElement;
272
Text: CustomText;
273
}
274
}
275
276
const withCustom = <T extends ReactEditor>(editor: T): T & { customMethod(): void } => {
277
editor.customMethod = () => {
278
console.log('Custom method called');
279
};
280
281
return editor as T & { customMethod(): void };
282
};
283
```
284
285
## Plugin System Best Practices
286
287
### Plugin Order
288
289
Apply plugins in the correct order for optimal functionality:
290
291
```typescript
292
// Recommended plugin order:
293
// 1. Core functionality plugins (history, etc.)
294
// 2. Custom business logic plugins
295
// 3. React plugin last
296
const editor = withReact(
297
withCustomLogic(
298
withHistory(
299
createEditor()
300
)
301
)
302
);
303
```
304
305
### Error Handling
306
307
Implement proper error handling in custom plugins:
308
309
```typescript
310
const withErrorHandling = <T extends ReactEditor>(editor: T): T => {
311
const { insertNode } = editor;
312
313
editor.insertNode = (node) => {
314
try {
315
insertNode(node);
316
} catch (error) {
317
console.error('Error inserting node:', error);
318
// Fallback behavior
319
}
320
};
321
322
return editor;
323
};
324
```
325
326
### Performance Considerations
327
328
Consider performance implications when creating custom plugins:
329
330
```typescript
331
const withPerformantPlugin = <T extends ReactEditor>(editor: T): T => {
332
// Cache expensive operations
333
const cache = new WeakMap();
334
335
editor.customOperation = (node) => {
336
if (cache.has(node)) {
337
return cache.get(node);
338
}
339
340
const result = expensiveOperation(node);
341
cache.set(node, result);
342
return result;
343
};
344
345
return editor;
346
};
347
```