Lexical provides React components for rendering editable content and handling errors.
ContentEditable
The editable content area where users interact with the editor.
import { ContentEditable } from '@lexical/react/LexicalContentEditable';
function Editor() {
return (
<ContentEditable
className="editor-input"
aria-placeholder="Enter some text..."
placeholder={
<div className="editor-placeholder">
Enter some text...
</div>
}
/>
);
}
Props
Extends all standard HTML <div> attributes except placeholder.
CSS class name for styling the editable area.
Accessible label for screen readers.
Accessible placeholder text. Required if using the placeholder prop.
placeholder
JSX.Element | ((isEditable: boolean) => JSX.Element | null) | null
Placeholder content displayed when the editor is empty. Can be a static element or a function that receives the editable state.
ARIA role. Defaults to "textbox".
Enable browser spell checking. Defaults to true.
Tab order for keyboard navigation.
ARIA active descendant for accessibility.
ariaAutoComplete
'none' | 'inline' | 'list' | 'both'
ARIA autocomplete attribute.
ARIA described-by attribute.
ARIA error message attribute.
ARIA labelled-by attribute.
ARIA multiline attribute.
HTML autocapitalize attribute for mobile devices.
Test ID for testing frameworks.
Ref
The component forwards a ref to the underlying <div> element:
const editorRef = useRef<HTMLDivElement>(null);
<ContentEditable ref={editorRef} />
ContentEditableElement
Lower-level version of ContentEditable that requires passing the editor instance explicitly. Used internally by ContentEditable.
import { ContentEditableElement } from '@lexical/react/LexicalContentEditable';
function CustomEditable() {
const [editor] = useLexicalComposerContext();
return (
<ContentEditableElement
editor={editor}
className="editor-input"
/>
);
}
Props
Same as ContentEditable props, plus:
The editor instance to attach to.
LexicalErrorBoundary
Error boundary component for catching and handling errors in decorators.
import { LexicalErrorBoundary } from '@lexical/react/LexicalErrorBoundary';
function Editor() {
const handleError = (error: Error) => {
console.error('Editor error:', error);
};
return (
<LexicalComposer initialConfig={config}>
<RichTextPlugin
contentEditable={<ContentEditable />}
placeholder={null}
ErrorBoundary={LexicalErrorBoundary}
/>
</LexicalComposer>
);
}
Props
Child elements to wrap with error boundary.
onError
(error: Error) => void
required
Callback invoked when an error is caught.
Behavior
When an error occurs, displays a red error message:
┌─────────────────────┐
│ An error was thrown.│
└─────────────────────┘
Advanced Components
LexicalTreeView
Development tool for visualizing the editor’s node tree.
import { TreeView } from '@lexical/react/LexicalTreeView';
function DebugEditor() {
const [editor] = useLexicalComposerContext();
return (
<div>
<ContentEditable />
<TreeView
editor={editor}
treeTypeButtonClassName="tree-type-button"
timeTravelButtonClassName="time-travel-button"
timeTravelPanelButtonClassName="time-travel-panel-button"
timeTravelPanelClassName="time-travel-panel"
timeTravelPanelSliderClassName="time-travel-panel-slider"
viewClassName="tree-view"
/>
</div>
);
}
Props: Class names for styling the tree view components.
DecoratorBlockNode
Base class for creating block-level decorator nodes. Not a React component, but a node class used with React.
import { DecoratorBlockNode } from '@lexical/react/LexicalDecoratorBlockNode';
class ImageNode extends DecoratorBlockNode {
static getType() {
return 'image';
}
decorate() {
return <ImageComponent nodeKey={this.getKey()} />;
}
}
See the Nodes API documentation for more details on creating custom nodes.
Styling Examples
Basic Editor Styling
.editor-input {
min-height: 150px;
resize: none;
font-size: 15px;
position: relative;
tab-size: 1;
outline: 0;
padding: 15px 10px;
caret-color: rgb(5, 5, 5);
}
.editor-placeholder {
color: #999;
overflow: hidden;
position: absolute;
text-overflow: ellipsis;
top: 15px;
left: 10px;
font-size: 15px;
user-select: none;
display: inline-block;
pointer-events: none;
}
Selected State
.editor-input:focus {
outline: 2px solid rgb(60, 132, 244);
}
[contenteditable="false"] .editor-input {
background-color: #f5f5f5;
}
With Placeholder Function
<ContentEditable
aria-placeholder="Start typing..."
placeholder={(isEditable) => (
<div className="editor-placeholder">
{isEditable ? 'Start typing...' : 'Read-only mode'}
</div>
)}
/>