0
# React Hooks
1
2
React hooks for accessing editor state, selection, focus, and other editor properties. These hooks provide the primary interface for interacting with Slate editors in React components and are essential for building interactive editor features.
3
4
## Capabilities
5
6
### Editor State Hooks
7
8
#### useSlate
9
10
Hook to get the current editor object and re-render the component whenever the editor changes.
11
12
```typescript { .api }
13
/**
14
* Get current editor object and re-render when it changes
15
* @returns The current editor instance
16
* @description Use this hook when your component needs to respond to editor state changes
17
*/
18
function useSlate(): Editor;
19
```
20
21
**Usage Example:**
22
23
```typescript
24
import React from 'react';
25
import { useSlate } from 'slate-react';
26
import { Editor, Transforms } from 'slate';
27
28
const BoldButton = () => {
29
const editor = useSlate();
30
31
const toggleBold = () => {
32
const isActive = Editor.marks(editor)?.bold === true;
33
if (isActive) {
34
Editor.removeMark(editor, 'bold');
35
} else {
36
Editor.addMark(editor, 'bold', true);
37
}
38
};
39
40
return (
41
<button
42
onMouseDown={(e) => {
43
e.preventDefault();
44
toggleBold();
45
}}
46
>
47
Bold
48
</button>
49
);
50
};
51
```
52
53
#### useSlateStatic
54
55
Hook to get the current editor object without triggering re-renders. Use this for event handlers and other operations that don't need to respond to editor changes.
56
57
```typescript { .api }
58
/**
59
* Get current editor object without triggering re-renders
60
* @returns The current editor instance
61
* @description Use this hook in event handlers and operations that don't need to re-render on editor changes
62
*/
63
function useSlateStatic(): Editor;
64
```
65
66
**Usage Example:**
67
68
```typescript
69
import React from 'react';
70
import { useSlateStatic } from 'slate-react';
71
import { Transforms } from 'slate';
72
73
const InsertButton = () => {
74
const editor = useSlateStatic();
75
76
const insertParagraph = () => {
77
Transforms.insertNodes(editor, {
78
type: 'paragraph',
79
children: [{ text: 'New paragraph' }]
80
});
81
};
82
83
return (
84
<button onClick={insertParagraph}>
85
Insert Paragraph
86
</button>
87
);
88
};
89
```
90
91
#### useEditor (deprecated)
92
93
Legacy hook for getting the editor object. Use `useSlateStatic` instead.
94
95
```typescript { .api }
96
/**
97
* Get current editor object (deprecated - use useSlateStatic instead)
98
* @returns The current editor instance
99
* @deprecated Use useSlateStatic instead
100
*/
101
function useEditor(): Editor;
102
```
103
104
#### useSlateWithV (deprecated)
105
106
Legacy hook that returns both editor and version counter. Use `useSlate` instead.
107
108
```typescript { .api }
109
/**
110
* Get editor object and version counter (deprecated - use useSlate instead)
111
* @returns Object with editor and version counter
112
* @deprecated Use useSlate instead
113
*/
114
function useSlateWithV(): { editor: Editor; v: number };
115
```
116
117
### Selection and Focus Hooks
118
119
#### useFocused
120
121
Hook to get the current focused state of the editor.
122
123
```typescript { .api }
124
/**
125
* Get current focused state of the editor
126
* @returns true if editor is focused, false otherwise
127
*/
128
function useFocused(): boolean;
129
```
130
131
**Usage Example:**
132
133
```typescript
134
import React from 'react';
135
import { useFocused } from 'slate-react';
136
137
const EditorStatus = () => {
138
const focused = useFocused();
139
140
return (
141
<div style={{
142
padding: '8px',
143
backgroundColor: focused ? 'lightblue' : 'lightgray'
144
}}>
145
Editor is {focused ? 'focused' : 'not focused'}
146
</div>
147
);
148
};
149
```
150
151
#### useSelected
152
153
Hook to get the current selected state of an element. Must be used within a render function.
154
155
```typescript { .api }
156
/**
157
* Get current selected state of an element
158
* @returns true if element is selected, false otherwise
159
* @description Must be used inside renderElement or similar render functions
160
*/
161
function useSelected(): boolean;
162
```
163
164
**Usage Example:**
165
166
```typescript
167
import React from 'react';
168
import { useSelected, RenderElementProps } from 'slate-react';
169
170
const CustomElement = ({ attributes, children, element }: RenderElementProps) => {
171
const selected = useSelected();
172
173
return (
174
<div
175
{...attributes}
176
style={{
177
border: selected ? '2px solid blue' : '1px solid gray',
178
padding: '8px'
179
}}
180
>
181
{children}
182
</div>
183
);
184
};
185
```
186
187
#### useSlateSelection
188
189
Hook to get the current Slate selection. Only re-renders when the selection changes, providing better performance than using `useSlate`.
190
191
```typescript { .api }
192
/**
193
* Get current slate selection (only re-renders when selection changes)
194
* @returns Current selection or null
195
* @description More performant than useSlate for selection-only operations
196
*/
197
function useSlateSelection(): BaseSelection;
198
```
199
200
**Usage Example:**
201
202
```typescript
203
import React from 'react';
204
import { useSlateSelection } from 'slate-react';
205
import { Range } from 'slate';
206
207
const SelectionInfo = () => {
208
const selection = useSlateSelection();
209
210
if (!selection) {
211
return <div>No selection</div>;
212
}
213
214
const isCollapsed = Range.isCollapsed(selection);
215
216
return (
217
<div>
218
Selection: {isCollapsed ? 'Cursor' : 'Range'} at
219
[{selection.anchor.path.join(', ')}:{selection.anchor.offset}]
220
</div>
221
);
222
};
223
```
224
225
### State Management Hooks
226
227
#### useReadOnly
228
229
Hook to get the current read-only state of the editor.
230
231
```typescript { .api }
232
/**
233
* Get current read-only state of the editor
234
* @returns true if editor is read-only, false otherwise
235
*/
236
function useReadOnly(): boolean;
237
```
238
239
**Usage Example:**
240
241
```typescript
242
import React from 'react';
243
import { useReadOnly } from 'slate-react';
244
245
const EditButton = () => {
246
const readOnly = useReadOnly();
247
248
return (
249
<button disabled={readOnly}>
250
{readOnly ? 'View Only' : 'Edit'}
251
</button>
252
);
253
};
254
```
255
256
#### useComposing
257
258
Hook to get the current composing state of the editor (useful for IME input handling).
259
260
```typescript { .api }
261
/**
262
* Get current composing state of the editor
263
* @returns true if user is composing text (e.g., with IME), false otherwise
264
*/
265
function useComposing(): boolean;
266
```
267
268
**Usage Example:**
269
270
```typescript
271
import React from 'react';
272
import { useComposing } from 'slate-react';
273
274
const ComposingIndicator = () => {
275
const composing = useComposing();
276
277
return composing ? (
278
<div style={{ color: 'orange' }}>Composing...</div>
279
) : null;
280
};
281
```
282
283
### Element Context Hooks
284
285
#### useElement
286
287
Hook to get the current element. Must be used within a `renderElement` function.
288
289
```typescript { .api }
290
/**
291
* Get current element (must be used inside renderElement)
292
* @returns The current element being rendered
293
* @throws Error if used outside of renderElement context
294
*/
295
function useElement(): Element;
296
```
297
298
#### useElementIf
299
300
Hook to get the current element, or return null if not inside `renderElement`. Safer alternative to `useElement`.
301
302
```typescript { .api }
303
/**
304
* Get current element, or return null if not inside renderElement
305
* @returns The current element being rendered, or null if not in renderElement context
306
*/
307
function useElementIf(): Element | null;
308
```
309
310
**Usage Example:**
311
312
```typescript
313
import React from 'react';
314
import { useElement, RenderElementProps } from 'slate-react';
315
316
const SmartElement = ({ attributes, children }: RenderElementProps) => {
317
const element = useElement();
318
319
// Access element properties for conditional rendering
320
const className = element.type === 'heading' ? 'heading-class' : 'paragraph-class';
321
322
return (
323
<div {...attributes} className={className}>
324
{children}
325
</div>
326
);
327
};
328
```
329
330
#### useElementIf
331
332
Hook to get the current element or null if not within a `renderElement` context.
333
334
```typescript { .api }
335
/**
336
* Get current element or null if not inside renderElement
337
* @returns The current element being rendered, or null if not in render context
338
*/
339
function useElementIf(): Element | null;
340
```
341
342
**Usage Example:**
343
344
```typescript
345
import React from 'react';
346
import { useElementIf } from 'slate-react';
347
348
const FlexibleComponent = () => {
349
const element = useElementIf();
350
351
if (element) {
352
return <div>Rendering element: {element.type}</div>;
353
}
354
355
return <div>Not in element context</div>;
356
};
357
```
358
359
## Hook Usage Patterns
360
361
### Combining Hooks for Complex UI
362
363
```typescript
364
import React from 'react';
365
import {
366
useSlate,
367
useFocused,
368
useSelected,
369
useSlateSelection,
370
RenderElementProps
371
} from 'slate-react';
372
import { Editor, Range } from 'slate';
373
374
const InteractiveElement = ({ attributes, children, element }: RenderElementProps) => {
375
const editor = useSlate();
376
const focused = useFocused();
377
const selected = useSelected();
378
const selection = useSlateSelection();
379
380
const hasTextSelection = selection && !Range.isCollapsed(selection);
381
const isActive = focused && (selected || hasTextSelection);
382
383
return (
384
<div
385
{...attributes}
386
style={{
387
border: isActive ? '2px solid blue' : '1px solid gray',
388
backgroundColor: selected ? '#f0f8ff' : 'transparent',
389
opacity: focused ? 1 : 0.7
390
}}
391
onDoubleClick={() => {
392
// Select entire element on double-click
393
const path = ReactEditor.findPath(editor, element);
394
Transforms.select(editor, path);
395
}}
396
>
397
{children}
398
</div>
399
);
400
};
401
```
402
403
### Performance Considerations
404
405
When using hooks in components that render frequently, consider performance implications:
406
407
- Use `useSlateStatic` for event handlers that don't need re-renders
408
- Use `useSlateSelection` instead of `useSlate` when only selection changes matter
409
- Memoize expensive computations with `useMemo` and `useCallback`
410
411
```typescript
412
import React, { useMemo, useCallback } from 'react';
413
import { useSlate, useSlateStatic } from 'slate-react';
414
import { Editor } from 'slate';
415
416
const OptimizedToolbar = () => {
417
const editor = useSlate(); // Re-renders on editor changes
418
const staticEditor = useSlateStatic(); // No re-renders
419
420
// Memoize expensive calculations
421
const isSelectionActive = useMemo(() => {
422
return !!editor.selection && !Range.isCollapsed(editor.selection);
423
}, [editor.selection]);
424
425
// Use static editor for event handlers
426
const handleBoldClick = useCallback(() => {
427
Editor.addMark(staticEditor, 'bold', true);
428
}, [staticEditor]);
429
430
return (
431
<div>
432
<button
433
disabled={!isSelectionActive}
434
onClick={handleBoldClick}
435
>
436
Bold
437
</button>
438
</div>
439
);
440
};
441
```