Are you happy with your logging solution? Would you help us out by taking a 30-second survey? Click here


Extensibly serialize & deserialize Draft.js ContentState with HTML.

Subscribe to updates I use draft-convert

Statistics on draft-convert

Number of watchers on Github 213
Number of open issues 32
Average time to close an issue 13 days
Main language JavaScript
Average time to merge a PR 7 days
Open pull requests 15+
Closed pull requests 14+
Last commit almost 2 years ago
Repo Created over 3 years ago
Repo Last Updated over 1 year ago
Size 221 KB
Organization / Authorhubspot
Latest Releasev2.0.1
Page Updated
Do you use draft-convert? Leave a review!
View open issues (32)
View on github
Fresh, new opensource launches 🚀🚀🚀
Trendy new open source projects in your inbox! View examples

Subscribe to our mailing list

Evaluating draft-convert for your project? Score Explanation
Commits Score (?)
Issues & PR Score (?)


npm version License

Extensibly serialize & deserialize Draft.js content with HTML

See draft-extend for more on how to use draft-convert with plugins


npm install draft-convert --save or yarn add draft-convert

Jump to:


Extensibly serialize Draft.js ContentState to HTML.

Basic usage:

const html = convertToHTML(editorState.getCurrentContent());

Advanced usage:

// convert to HTML with blue text, paragraphs, and links
const html = convertToHTML({
  styleToHTML: (style) => {
    if (style === 'BOLD') {
      return <span style={{color: 'blue'}} />;
  blockToHTML: (block) => {
    if (block.type === 'PARAGRAPH') {
      return <p />;
  entityToHTML: (entity, originalText) => {
    if (entity.type === 'LINK') {
      return <a href={}>{originalText}</a>;
    return originalText;

// convert content state to HTML with functionality defined in the plugins applied
const html = compose(

styleToHTML, blockToHtml, and entityToHTML are functions that take Draft content data and may return a ReactElement or an object of shape {start, end} defining strings for the beginning and end tags of the style, block, or entity. entityToHTML may return either a string with or without HTML if the use case demands it. blockToHTML also may return an optional empty property to handle alternative behavior for empty blocks. To use this along with a ReactElement return value an object of shape {element: ReactElement, empty: ReactElement} may be returned. If no additional functionality is necessary convertToHTML can be invoked with just a ContentState to serialize using just the default Draft functionality. convertToHTML can be passed as an argument to a plugin to modularly augment its functionality.

Legacy alternative conversion options styleToHTML and blockToHTML options may be plain objects keyed by style or block type with values of ReactElement s or {start, end} objects. These objects will eventually be removed in favor of the functions described above.

Type info:

type ContentStateConverter = (contentState: ContentState) => string

type Tag =
  ReactElement |
  {start: string, end: string, empty?: string} |
  {element: ReactElement, empty?: ReactElement}

type RawEntity = {
    type: string,
    mutability: DraftEntityMutability,
    data: Object

type RawBlock = {
    type: string,
    depth: number,
    data?: object,
    text: string

type convertToHTML = ContentStateConverter | ({
    styleToHTML?: (style: string) => Tag,
    blockToHTML?: (block: RawBlock) => Tag),
    entityToHTML?: (entity: RawEntity, originalText: string) => Tag | string
}) => ContentStateConverter


Extensibly deserialize HTML to Draft.js ContentState.

Basic usage:

const editorState = EditorState.createWithContent(convertFromHTML(html));

Advanced usage:

// convert HTML to ContentState with blue text, links, and at-mentions
const contentState = convertFromHTML({
    htmlToStyle: (nodeName, node, currentStyle) => {
        if (nodeName === 'span' && === 'blue') {
            return currentStyle.add('BLUE');
        } else {
            return currentStyle;
    htmlToEntity: (nodeName, node, createEntity) => {
        if (nodeName === 'a') {
            return createEntity(
                {url: node.href}
    textToEntity: (text, createEntity) => {
        const result = [];
        text.replace(/\@(\w+)/g, (match, name, offset) => {
            const entityKey = createEntity(
                entity: entityKey,
                length: match.length,
                result: match
        return result;
    htmlToBlock: (nodeName, node) => {
        if (nodeName === 'blockquote') {
            return {
                type: 'blockquote',
                data: {}

// convert HTML to ContentState with functionality defined in the plugins applied
const contentState = compose(

If no additional functionality is necessary convertToHTML can be invoked with just an HTML string to deserialize using just the default Draft functionality. Any convertFromHTML can be passed as an argument to a plugin to modularly augment its functionality. A flat option may be provided to force nested block elements to split into flat, separate blocks. For example, the HTML input <p>line one<br />linetwo</p> will produce two unstyled blocks in flat mode.

Type info:

type HTMLConverter = (html: string, {flat: ?boolean}, DOMBuilder: ?Function) => ContentState

type EntityKey = string

type convertFromHTML = HTMLConverter | ({
    htmlToStyle: ?(nodeName: string, node: Node) => DraftInlineStyle,
    htmlToBlock: ?(nodeName: string, node: Node) => ?(DraftBlockType | {type: DraftBlockType, data: object} | false),
    htmlToEntity: ?(
        nodeName: string,
        node: string,
        createEntity: (type: string, mutability: string, data: object) => EntityKey,
        getEntity: (key: EntityKey) => Entity,
        mergeEntityData: (key: string, data: object) => void,
        replaceEntityData: (key: string, data: object) => void
    ): ?EntityKey,
    textToEntity: ?(
        text: string,
        createEntity: (type: string, mutability: string, data: object) => EntityKey,
        getEntity: (key: EntityKey) => Entity,
        mergeEntityData: (key: string, data: object) => void,
        replaceEntityData: (key: string, data: object) => void
    ) => Array<{entity: EntityKey, offset: number, length: number, result: ?string}>
}) => HTMLConverter

Middleware functions

Any conversion option for convertToHTML or convertFromHTML may also accept a middleware function of shape (next) => (args) => result , where args are the normal configuration function paramaters and result is the expected return type for that function. These functions can transform results of the default conversion included in convertToHTML or convertFromHTML by leveraging the result of next(...args). These middleware functions are most useful when passed as the result of composition of draft-extend plugins. If you choose to use them independently, a __isMiddleware property must be set to true on the function for draft-convert to properly handle it.

draft-convert open issues Ask a question     (View All Issues)
  • almost 3 years Using convertToHTML returning an <img> tag in blockToHTML gives error
  • almost 3 years HTML Node to multiple Content blocks
  • almost 3 years convertFromHTML is processing newlines in lists wrong
  • about 3 years is it possible to support <sup> and <sub> tags using this library?
  • about 3 years convertToHTML outputting unexpected character
  • about 3 years Wrong import of html tag "blockquote"
  • about 3 years convertFromHTML tag <img /> problem
draft-convert open pull requests (View All Pulls)
  • Update build scripts and linting
  • handle BR tags within list items by converting them to newlines
  • Add failing test for overlapping styles in entity.
  • Emoji/Unicode support - fixes #12
  • fix void elements in entityToHTML
  • prettier
  • Update
  • Fix the type of node in convertFromHTML signature
  • Handle offsets in encodeBlock with emojis involved
  • Bump immutable to 3.8.1
  • HubSpot issue 79
  • Fix double escaping of entities.
  • Added Nested Block support for "code-block"
  • encode '\xA0' to '&nbsp;'
  • Custom nested block types
draft-convert list of languages used
draft-convert latest release notes
v2.0.1 v2.0.1


  • Support React 16 (#106)
v2.0.0 v2.0.0


  • Update Entity conversion to use new draft-js@0.10.0 Entity API (#82)
    • This change will require some changes to conversion from HTML to entities - instead of using Entity.create within htmlToEntity and textToEntity, both methods now receive createEntity, getEntity, mergeEntityData, and replaceEntityData to use for creating or modifying entities. These provided methods are compatible with both the old and new Entity APIs.
v1.4.10 v1.4.10


  • Remove __version export and json-loader dependency (#96)
Other projects in JavaScript