Functions for converting between Draft.js content and other formats including raw objects for serialization and HTML for import/export.
Functions for converting between Draft.js ContentState and plain JavaScript objects suitable for JSON serialization.
Converts a ContentState to a raw JavaScript object that can be serialized to JSON.
/**
* Convert ContentState to raw object for serialization
* @param contentState - ContentState to convert
* @returns Raw state object suitable for JSON serialization
*/
function convertToRaw(contentState: ContentState): RawDraftContentState;Converts a raw JavaScript object back to a ContentState.
/**
* Convert raw object to ContentState
* @param rawState - Raw state object from JSON deserialization
* @returns ContentState instance
*/
function convertFromRaw(rawState: RawDraftContentState): ContentState;Usage Examples:
import { convertToRaw, convertFromRaw, EditorState } from "draft-js";
// Save editor content to storage
function saveContent(editorState) {
const contentState = editorState.getCurrentContent();
const rawContentState = convertToRaw(contentState);
// Save to localStorage
localStorage.setItem('draft-content', JSON.stringify(rawContentState));
// Or send to server
fetch('/api/save-content', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ content: rawContentState })
});
}
// Load editor content from storage
function loadContent() {
const rawContentState = JSON.parse(
localStorage.getItem('draft-content') || '{"blocks":[],"entityMap":{}}'
);
const contentState = convertFromRaw(rawContentState);
return EditorState.createWithContent(contentState);
}
// Working with raw content
function analyzeRawContent(rawContentState) {
console.log('Number of blocks:', rawContentState.blocks.length);
console.log('Number of entities:', Object.keys(rawContentState.entityMap).length);
rawContentState.blocks.forEach((block, index) => {
console.log(`Block ${index}: ${block.type} - "${block.text}"`);
});
}
// Modify raw content
function addPrefixToRawContent(rawContentState, prefix) {
return {
...rawContentState,
blocks: rawContentState.blocks.map((block, index) => {
if (index === 0) {
return {
...block,
text: prefix + block.text
};
}
return block;
})
};
}Function for converting HTML strings to Draft.js content blocks.
Converts HTML string to Draft.js content blocks and entities.
/**
* Convert HTML string to Draft.js content blocks
* @param html - HTML string to convert
* @param getSafeBodyFromHTML - Optional function to sanitize HTML
* @param blockRenderMap - Optional block render map for custom elements
* @returns Object containing content blocks and entity map
*/
function convertFromHTML(
html: string,
getSafeBodyFromHTML?: (html: string) => HTMLElement,
blockRenderMap?: DraftBlockRenderMap
): {
contentBlocks: Array<ContentBlock>,
entityMap: any
};Usage Examples:
import { convertFromHTML, ContentState, EditorState } from "draft-js";
// Convert HTML to editor state
function htmlToEditorState(html) {
const { contentBlocks, entityMap } = convertFromHTML(html);
if (contentBlocks) {
const contentState = ContentState.createFromBlockArray(
contentBlocks,
entityMap
);
return EditorState.createWithContent(contentState);
}
return EditorState.createEmpty();
}
// Import HTML content
function importHtmlContent(htmlString) {
// Basic HTML import
const editorState = htmlToEditorState(htmlString);
return editorState;
}
// Import with custom sanitization
function importSanitizedHtml(htmlString) {
const getSafeBodyFromHTML = (html) => {
// Create temporary DOM element
const doc = new DOMParser().parseFromString(html, 'text/html');
// Remove dangerous elements
const scripts = doc.querySelectorAll('script');
scripts.forEach(script => script.remove());
return doc.body;
};
const { contentBlocks, entityMap } = convertFromHTML(
htmlString,
getSafeBodyFromHTML
);
if (contentBlocks) {
const contentState = ContentState.createFromBlockArray(
contentBlocks,
entityMap
);
return EditorState.createWithContent(contentState);
}
return EditorState.createEmpty();
}
// Handle paste from HTML
function handlePastedText(text, html, editorState) {
if (html) {
const { contentBlocks, entityMap } = convertFromHTML(html);
if (contentBlocks) {
const contentState = editorState.getCurrentContent();
const selection = editorState.getSelection();
// Create fragment from pasted content
const pastedContentState = ContentState.createFromBlockArray(
contentBlocks,
entityMap
);
const fragment = pastedContentState.getBlockMap();
// Insert fragment
const newContentState = Modifier.replaceWithFragment(
contentState,
selection,
fragment
);
const newEditorState = EditorState.push(
editorState,
newContentState,
'insert-fragment'
);
return newEditorState;
}
}
return null; // Fall back to default handling
}Utility functions for exporting Draft.js content to various formats.
/**
* Export utilities for converting Draft.js content to other formats
*/
// Export to plain text
function exportToPlainText(contentState: ContentState, delimiter?: string): string {
return contentState.getPlainText(delimiter || '\n');
}
// Export to HTML (basic implementation)
function exportToHTML(contentState: ContentState): string {
const blocks = contentState.getBlocksAsArray();
return blocks.map(block => {
const text = block.getText();
const type = block.getType();
switch (type) {
case 'header-one':
return `<h1>${text}</h1>`;
case 'header-two':
return `<h2>${text}</h2>`;
case 'header-three':
return `<h3>${text}</h3>`;
case 'blockquote':
return `<blockquote>${text}</blockquote>`;
case 'code-block':
return `<pre><code>${text}</code></pre>`;
case 'unordered-list-item':
return `<li>${text}</li>`;
case 'ordered-list-item':
return `<li>${text}</li>`;
default:
return `<p>${text}</p>`;
}
}).join('\n');
}
// Export with inline styles and entities
function exportToRichHTML(contentState: ContentState): string {
const blocks = contentState.getBlocksAsArray();
return blocks.map(block => {
let html = '';
const text = block.getText();
const type = block.getType();
const characterList = block.getCharacterList();
// Process character by character for inline styles
for (let i = 0; i < text.length; i++) {
const char = text[i];
const metadata = characterList.get(i);
const styles = metadata.getStyle();
const entityKey = metadata.getEntity();
let styledChar = char;
// Apply inline styles
if (styles.has('BOLD')) {
styledChar = `<strong>${styledChar}</strong>`;
}
if (styles.has('ITALIC')) {
styledChar = `<em>${styledChar}</em>`;
}
if (styles.has('UNDERLINE')) {
styledChar = `<u>${styledChar}</u>`;
}
// Apply entities
if (entityKey) {
const entity = contentState.getEntity(entityKey);
if (entity.getType() === 'LINK') {
const { url } = entity.getData();
styledChar = `<a href="${url}">${styledChar}</a>`;
}
}
html += styledChar;
}
// Wrap in block element
switch (type) {
case 'header-one':
return `<h1>${html}</h1>`;
case 'header-two':
return `<h2>${html}</h2>`;
case 'header-three':
return `<h3>${html}</h3>`;
case 'blockquote':
return `<blockquote>${html}</blockquote>`;
case 'code-block':
return `<pre><code>${html}</code></pre>`;
default:
return `<p>${html}</p>`;
}
}).join('\n');
}Complete Export Example:
import { convertToRaw, EditorState } from "draft-js";
// Multi-format export utility
class ContentExporter {
static exportAs(editorState, format) {
const contentState = editorState.getCurrentContent();
switch (format) {
case 'raw':
return convertToRaw(contentState);
case 'json':
return JSON.stringify(convertToRaw(contentState), null, 2);
case 'plain':
return contentState.getPlainText('\n');
case 'html':
return this.exportToHTML(contentState);
case 'markdown':
return this.exportToMarkdown(contentState);
default:
throw new Error(`Unsupported export format: ${format}`);
}
}
static exportToHTML(contentState) {
// Implementation for HTML export with styles and entities
return exportToRichHTML(contentState);
}
static exportToMarkdown(contentState) {
const blocks = contentState.getBlocksAsArray();
return blocks.map(block => {
const text = block.getText();
const type = block.getType();
switch (type) {
case 'header-one':
return `# ${text}`;
case 'header-two':
return `## ${text}`;
case 'header-three':
return `### ${text}`;
case 'blockquote':
return `> ${text}`;
case 'code-block':
return `\`\`\`\n${text}\n\`\`\``;
case 'unordered-list-item':
return `- ${text}`;
case 'ordered-list-item':
return `1. ${text}`;
default:
return text;
}
}).join('\n\n');
}
}
// Usage
function exportContent(editorState, format) {
try {
const exported = ContentExporter.exportAs(editorState, format);
console.log(`Exported as ${format}:`, exported);
return exported;
} catch (error) {
console.error('Export failed:', error);
return null;
}
}// Raw content state structure
interface RawDraftContentState {
blocks: Array<RawDraftContentBlock>;
entityMap: {[key: string]: RawDraftEntity};
}
// Raw content block
interface RawDraftContentBlock {
key: string;
type: DraftBlockType;
text: string;
characterList: Array<RawDraftCharacterMetadata>;
depth: number;
data?: {[key: string]: any};
}
// Raw entity
interface RawDraftEntity {
type: DraftEntityType;
mutability: DraftEntityMutability;
data: {[key: string]: any};
}
// Raw character metadata
interface RawDraftCharacterMetadata {
style: Array<string>;
entity: ?string;
}
// HTML conversion result
interface HTMLConversionResult {
contentBlocks: Array<ContentBlock>;
entityMap: any;
}
// Block render map for HTML conversion
type DraftBlockRenderMap = Immutable.Map<DraftBlockType, DraftBlockRenderConfig>;
interface DraftBlockRenderConfig {
element: string;
wrapper?: React.ComponentType<any>;
aliasedElements?: Array<string>;
}