Draft.js is a React framework for building rich text editors with immutable data models. It provides a comprehensive set of tools for creating sophisticated text composition experiences with full control over styling, entity management, and editor behavior.
npm install draft-jsimport {
Editor,
EditorState,
ContentState,
SelectionState,
Modifier,
RichUtils,
convertFromRaw,
convertToRaw,
} from "draft-js";For CommonJS:
const {
Editor,
EditorState,
ContentState,
SelectionState,
Modifier,
RichUtils,
convertFromRaw,
convertToRaw,
} = require("draft-js");Don't forget to include the CSS:
import "draft-js/dist/Draft.css";import React, { useState } from "react";
import { Editor, EditorState, RichUtils } from "draft-js";
import "draft-js/dist/Draft.css";
function MyEditor() {
const [editorState, setEditorState] = useState(
EditorState.createEmpty()
);
const handleKeyCommand = (command, editorState) => {
const newState = RichUtils.handleKeyCommand(editorState, command);
if (newState) {
setEditorState(newState);
return "handled";
}
return "not-handled";
};
const toggleBold = () => {
setEditorState(RichUtils.toggleInlineStyle(editorState, "BOLD"));
};
return (
<div>
<button onClick={toggleBold}>Bold</button>
<Editor
editorState={editorState}
onChange={setEditorState}
handleKeyCommand={handleKeyCommand}
placeholder="Start typing..."
/>
</div>
);
}Draft.js is built around several key concepts:
Core React components for rendering the rich text editor interface.
// Main editor component
const Editor: React.ComponentType<{
editorState: EditorState,
onChange: (editorState: EditorState) => void,
placeholder?: string,
readOnly?: boolean,
customStyleMap?: {[styleName: string]: React.CSSProperties},
blockRenderMap?: Immutable.Map<string, any>,
keyBindingFn?: (e: SyntheticKeyboardEvent) => ?string,
handleKeyCommand?: (command: string, editorState: EditorState) => 'handled' | 'not-handled',
// ... many more props
}>;
// Individual block component
const EditorBlock: React.ComponentType<any>;Immutable data structures that represent editor state, content, and selections.
// Central editor state
class EditorState {
static createEmpty(decorator?: DraftDecoratorType): EditorState;
static createWithText(text: string, decorator?: DraftDecoratorType): EditorState;
static createWithContent(contentState: ContentState, decorator?: DraftDecoratorType): EditorState;
getCurrentContent(): ContentState;
getSelection(): SelectionState;
push(contentState: ContentState, changeType: EditorChangeType): EditorState;
undo(): EditorState;
redo(): EditorState;
}
// Content representation
class ContentState {
static createFromText(text: string, delimiter?: string | RegExp): ContentState;
static createFromBlockArray(blocks: Array<ContentBlock>, entityMap?: any): ContentState;
getBlockMap(): BlockMap;
getPlainText(delimiter?: string): string;
getBlockForKey(key: string): ContentBlock;
}
// Selection state
class SelectionState {
getStartKey(): string;
getStartOffset(): number;
getEndKey(): string;
getEndOffset(): number;
isCollapsed(): boolean;
}Utilities for making changes to editor content with proper immutable updates.
// Low-level content modification
const Modifier: {
replaceText(contentState: ContentState, targetRange: SelectionState, text: string, inlineStyle?: DraftInlineStyle, entityKey?: ?string): ContentState;
insertText(contentState: ContentState, targetRange: SelectionState, text: string, inlineStyle?: DraftInlineStyle, entityKey?: ?string): ContentState;
applyInlineStyle(contentState: ContentState, targetRange: SelectionState, inlineStyle: string): ContentState;
removeInlineStyle(contentState: ContentState, targetRange: SelectionState, inlineStyle: string): ContentState;
setBlockType(contentState: ContentState, targetRange: SelectionState, blockType: DraftBlockType): ContentState;
applyEntity(contentState: ContentState, targetRange: SelectionState, entityKey: ?string): ContentState;
};
// High-level rich text utilities
const RichUtils: {
handleKeyCommand(editorState: EditorState, command: DraftEditorCommand): ?EditorState;
toggleInlineStyle(editorState: EditorState, inlineStyle: string): EditorState;
toggleBlockType(editorState: EditorState, blockType: DraftBlockType): EditorState;
toggleLink(editorState: EditorState, targetSelection: SelectionState, entityKey: ?string): EditorState;
insertSoftNewline(editorState: EditorState): EditorState;
};
// Atomic block utilities
const AtomicBlockUtils: {
insertAtomicBlock(editorState: EditorState, entityKey: string, character: string): EditorState;
moveAtomicBlock(editorState: EditorState, atomicBlock: ContentBlock, targetRange: SelectionState, insertionMode?: DraftInsertionType): EditorState;
};System for managing rich content entities like links, images, and embedded media.
// Entity management (legacy API)
const Entity: {
create(type: DraftEntityType, mutability: DraftEntityMutability, data?: any): string;
get(key: string): DraftEntityInstance;
mergeData(key: string, toMerge: {[key: string]: any}): void;
replaceData(key: string, newData: {[key: string]: any}): void;
};
// Entity instance
class DraftEntityInstance {
getType(): DraftEntityType;
getMutability(): DraftEntityMutability;
getData(): any;
}
// Composite decorator
class CompositeDecorator {
constructor(decorators: Array<DraftDecoratorType>);
getDecorations(block: ContentBlock, contentState: ContentState): List<string>;
getComponentForKey(key: string): Function;
getPropsForKey(key: string): any;
}Functions for converting between Draft.js content and other formats (raw objects, HTML).
// Raw state conversion
function convertToRaw(contentState: ContentState): RawDraftContentState;
function convertFromRaw(rawState: RawDraftContentState): ContentState;
// HTML conversion
function convertFromHTML(html: string, getSafeBodyFromHTML?: Function, blockRenderMap?: DraftBlockRenderMap): {
contentBlocks: Array<ContentBlock>,
entityMap: any
};Utilities for key binding management and miscellaneous helper functions.
// Key binding utilities
const KeyBindingUtil: {
isCtrlKeyCommand(e: SyntheticKeyboardEvent): boolean;
isOptionKeyCommand(e: SyntheticKeyboardEvent): boolean;
hasCommandModifier(e: SyntheticKeyboardEvent): boolean;
};
// Default key binding function
function getDefaultKeyBinding(e: SyntheticKeyboardEvent): ?string;
// Key generation
function genKey(): string;
// Selection utilities
function getVisibleSelectionRect(window: DOMWindow): ?ClientRect;
// Block map builder
const BlockMapBuilder: {
createFromArray(blocks: Array<ContentBlock>): BlockMap;
};Default configuration objects for block rendering and inline styling.
// Default block render map - maps block types to HTML elements
const DefaultDraftBlockRenderMap: Immutable.Map<DraftBlockType, DraftBlockRenderConfig>;
// Default inline style map - CSS properties for built-in styles
const DefaultDraftInlineStyle: {
BOLD: {fontWeight: 'bold'},
CODE: {fontFamily: 'monospace', wordWrap: 'break-word'},
ITALIC: {fontStyle: 'italic'},
STRIKETHROUGH: {textDecoration: 'line-through'},
UNDERLINE: {textDecoration: 'underline'}
};
// Raw content state type definition
type RawDraftContentState: {
blocks: Array<RawDraftContentBlock>,
entityMap: {[key: string]: RawDraftEntity}
};// Block types
type DraftBlockType = 'paragraph' | 'header-one' | 'header-two' | 'header-three' |
'header-four' | 'header-five' | 'header-six' | 'unordered-list-item' |
'ordered-list-item' | 'blockquote' | 'code-block' | 'atomic' | 'unstyled';
// Inline style
type DraftInlineStyle = OrderedSet<string>;
// Entity types
type DraftEntityType = string;
type DraftEntityMutability = 'MUTABLE' | 'IMMUTABLE' | 'SEGMENTED';
// Editor commands
type DraftEditorCommand = 'backspace' | 'backspace-word' | 'backspace-to-start-of-line' |
'delete' | 'delete-word' | 'delete-to-end-of-block' | 'enter' | 'forward-delete' |
'insert-characters' | 'insert-compose-character' | 'move-selection-to-start-of-block' |
'move-selection-to-end-of-block' | 'secondary-cut' | 'secondary-paste' | 'split-block' |
'transpose-characters' | 'undo' | 'redo' | 'bold' | 'code' | 'italic' | 'strikethrough' |
'underline';
// Change types
type EditorChangeType = 'adjust-depth' | 'apply-entity' | 'backspace-character' |
'change-block-data' | 'change-block-type' | 'change-inline-style' | 'move-block' |
'delete-character' | 'insert-characters' | 'insert-fragment' | 'redo' | 'remove-range' |
'spellcheck-change' | 'split-block' | 'undo';
// Handle values
type DraftHandleValue = 'handled' | 'not-handled';
// Drag types
type DraftDragType = 'internal' | 'external';
// Text alignment and directionality
type DraftTextAlignment = 'left' | 'center' | 'right';
type DraftTextDirectionality = 'LTR' | 'RTL' | 'NEUTRAL';
// Insertion mode for atomic blocks
type DraftInsertionType = 'replace' | 'before' | 'after';
// Removal direction
type DraftRemovalDirection = 'backward' | 'forward';
// Raw content state
interface RawDraftContentState {
blocks: Array<RawDraftContentBlock>;
entityMap: {[key: string]: RawDraftEntity};
}
interface RawDraftContentBlock {
key: string;
type: DraftBlockType;
text: string;
characterList: Array<RawDraftCharacterMetadata>;
depth: number;
data?: {[key: string]: any};
}
interface RawDraftEntity {
type: DraftEntityType;
mutability: DraftEntityMutability;
data: {[key: string]: any};
}
interface RawDraftCharacterMetadata {
style: Array<string>;
entity: ?string;
}// Block render map - maps block types to HTML elements
type DraftBlockRenderMap = Immutable.Map<DraftBlockType, DraftBlockRenderConfig>;
interface DraftBlockRenderConfig {
element: string;
wrapper?: React.ComponentType<any>;
aliasedElements?: Array<string>;
}
// Inline style map - maps style names to CSS properties
type DraftStyleMap = {[styleName: string]: React.CSSProperties};
// Decorator configuration
interface DraftDecoratorType {
getDecorations(block: ContentBlock, contentState: ContentState): ?Array<?string>;
getComponentForKey(key: string): Function;
getPropsForKey(key: string): any;
}
// Immutable data types
type OrderedSet<T> = any; // From Immutable.js
type OrderedMap<K, V> = any; // From Immutable.js
type List<T> = any; // From Immutable.js
type Stack<T> = any; // From Immutable.js
type BlockMap = OrderedMap<string, ContentBlock>;
// React event types
type SyntheticKeyboardEvent = any;
type SyntheticEvent = any;
type SyntheticClipboardEvent = any;
// DOM types
type DOMWindow = any;
type ClientRect = any;
type EntityMap = any;