React components and hooks for building customizable rich text editors using the Slate framework.
—
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.
Hook to get the current editor object and re-render the component whenever the editor changes.
/**
* Get current editor object and re-render when it changes
* @returns The current editor instance
* @description Use this hook when your component needs to respond to editor state changes
*/
function useSlate(): Editor;Usage Example:
import React from 'react';
import { useSlate } from 'slate-react';
import { Editor, Transforms } from 'slate';
const BoldButton = () => {
const editor = useSlate();
const toggleBold = () => {
const isActive = Editor.marks(editor)?.bold === true;
if (isActive) {
Editor.removeMark(editor, 'bold');
} else {
Editor.addMark(editor, 'bold', true);
}
};
return (
<button
onMouseDown={(e) => {
e.preventDefault();
toggleBold();
}}
>
Bold
</button>
);
};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.
/**
* Get current editor object without triggering re-renders
* @returns The current editor instance
* @description Use this hook in event handlers and operations that don't need to re-render on editor changes
*/
function useSlateStatic(): Editor;Usage Example:
import React from 'react';
import { useSlateStatic } from 'slate-react';
import { Transforms } from 'slate';
const InsertButton = () => {
const editor = useSlateStatic();
const insertParagraph = () => {
Transforms.insertNodes(editor, {
type: 'paragraph',
children: [{ text: 'New paragraph' }]
});
};
return (
<button onClick={insertParagraph}>
Insert Paragraph
</button>
);
};Legacy hook for getting the editor object. Use useSlateStatic instead.
/**
* Get current editor object (deprecated - use useSlateStatic instead)
* @returns The current editor instance
* @deprecated Use useSlateStatic instead
*/
function useEditor(): Editor;Legacy hook that returns both editor and version counter. Use useSlate instead.
/**
* Get editor object and version counter (deprecated - use useSlate instead)
* @returns Object with editor and version counter
* @deprecated Use useSlate instead
*/
function useSlateWithV(): { editor: Editor; v: number };Hook to get the current focused state of the editor.
/**
* Get current focused state of the editor
* @returns true if editor is focused, false otherwise
*/
function useFocused(): boolean;Usage Example:
import React from 'react';
import { useFocused } from 'slate-react';
const EditorStatus = () => {
const focused = useFocused();
return (
<div style={{
padding: '8px',
backgroundColor: focused ? 'lightblue' : 'lightgray'
}}>
Editor is {focused ? 'focused' : 'not focused'}
</div>
);
};Hook to get the current selected state of an element. Must be used within a render function.
/**
* Get current selected state of an element
* @returns true if element is selected, false otherwise
* @description Must be used inside renderElement or similar render functions
*/
function useSelected(): boolean;Usage Example:
import React from 'react';
import { useSelected, RenderElementProps } from 'slate-react';
const CustomElement = ({ attributes, children, element }: RenderElementProps) => {
const selected = useSelected();
return (
<div
{...attributes}
style={{
border: selected ? '2px solid blue' : '1px solid gray',
padding: '8px'
}}
>
{children}
</div>
);
};Hook to get the current Slate selection. Only re-renders when the selection changes, providing better performance than using useSlate.
/**
* Get current slate selection (only re-renders when selection changes)
* @returns Current selection or null
* @description More performant than useSlate for selection-only operations
*/
function useSlateSelection(): BaseSelection;Usage Example:
import React from 'react';
import { useSlateSelection } from 'slate-react';
import { Range } from 'slate';
const SelectionInfo = () => {
const selection = useSlateSelection();
if (!selection) {
return <div>No selection</div>;
}
const isCollapsed = Range.isCollapsed(selection);
return (
<div>
Selection: {isCollapsed ? 'Cursor' : 'Range'} at
[{selection.anchor.path.join(', ')}:{selection.anchor.offset}]
</div>
);
};Hook to get the current read-only state of the editor.
/**
* Get current read-only state of the editor
* @returns true if editor is read-only, false otherwise
*/
function useReadOnly(): boolean;Usage Example:
import React from 'react';
import { useReadOnly } from 'slate-react';
const EditButton = () => {
const readOnly = useReadOnly();
return (
<button disabled={readOnly}>
{readOnly ? 'View Only' : 'Edit'}
</button>
);
};Hook to get the current composing state of the editor (useful for IME input handling).
/**
* Get current composing state of the editor
* @returns true if user is composing text (e.g., with IME), false otherwise
*/
function useComposing(): boolean;Usage Example:
import React from 'react';
import { useComposing } from 'slate-react';
const ComposingIndicator = () => {
const composing = useComposing();
return composing ? (
<div style={{ color: 'orange' }}>Composing...</div>
) : null;
};Hook to get the current element. Must be used within a renderElement function.
/**
* Get current element (must be used inside renderElement)
* @returns The current element being rendered
* @throws Error if used outside of renderElement context
*/
function useElement(): Element;Hook to get the current element, or return null if not inside renderElement. Safer alternative to useElement.
/**
* Get current element, or return null if not inside renderElement
* @returns The current element being rendered, or null if not in renderElement context
*/
function useElementIf(): Element | null;Usage Example:
import React from 'react';
import { useElement, RenderElementProps } from 'slate-react';
const SmartElement = ({ attributes, children }: RenderElementProps) => {
const element = useElement();
// Access element properties for conditional rendering
const className = element.type === 'heading' ? 'heading-class' : 'paragraph-class';
return (
<div {...attributes} className={className}>
{children}
</div>
);
};Hook to get the current element or null if not within a renderElement context.
/**
* Get current element or null if not inside renderElement
* @returns The current element being rendered, or null if not in render context
*/
function useElementIf(): Element | null;Usage Example:
import React from 'react';
import { useElementIf } from 'slate-react';
const FlexibleComponent = () => {
const element = useElementIf();
if (element) {
return <div>Rendering element: {element.type}</div>;
}
return <div>Not in element context</div>;
};import React from 'react';
import {
useSlate,
useFocused,
useSelected,
useSlateSelection,
RenderElementProps
} from 'slate-react';
import { Editor, Range } from 'slate';
const InteractiveElement = ({ attributes, children, element }: RenderElementProps) => {
const editor = useSlate();
const focused = useFocused();
const selected = useSelected();
const selection = useSlateSelection();
const hasTextSelection = selection && !Range.isCollapsed(selection);
const isActive = focused && (selected || hasTextSelection);
return (
<div
{...attributes}
style={{
border: isActive ? '2px solid blue' : '1px solid gray',
backgroundColor: selected ? '#f0f8ff' : 'transparent',
opacity: focused ? 1 : 0.7
}}
onDoubleClick={() => {
// Select entire element on double-click
const path = ReactEditor.findPath(editor, element);
Transforms.select(editor, path);
}}
>
{children}
</div>
);
};When using hooks in components that render frequently, consider performance implications:
useSlateStatic for event handlers that don't need re-rendersuseSlateSelection instead of useSlate when only selection changes matteruseMemo and useCallbackimport React, { useMemo, useCallback } from 'react';
import { useSlate, useSlateStatic } from 'slate-react';
import { Editor } from 'slate';
const OptimizedToolbar = () => {
const editor = useSlate(); // Re-renders on editor changes
const staticEditor = useSlateStatic(); // No re-renders
// Memoize expensive calculations
const isSelectionActive = useMemo(() => {
return !!editor.selection && !Range.isCollapsed(editor.selection);
}, [editor.selection]);
// Use static editor for event handlers
const handleBoldClick = useCallback(() => {
Editor.addMark(staticEditor, 'bold', true);
}, [staticEditor]);
return (
<div>
<button
disabled={!isSelectionActive}
onClick={handleBoldClick}
>
Bold
</button>
</div>
);
};Install with Tessl CLI
npx tessl i tessl/npm-slate-react